c snprintf用于连接字符串

Tim*_*ann 1 c linux string

我在两台不同的计算机上使用以下功能.一台计算机运行Ubuntu,另一台运行OS X.该功能适用​​于OS X,但不适用于Ubuntu.

#include <stdio.h>

#define MAXBUF 256

char *safe_strncat(char *dest, const char *src, size_t n) {
    snprintf(dest, n, "%s%s", dest, src);
    return dest;
}

int main(int argc, const char * argv[]){
    char st1[MAXBUF+1] = "abc";
    char st2[MAXBUF+1] = "def";
    char* st3;
    printf("%s + %s = ",st1, st2);

    st3 = safe_strncat(st1, st2, MAXBUF);

    printf("%s\n",st3);
    printf("original string = %s\n",st1);
}
Run Code Online (Sandbox Code Playgroud)

编译并在Ubuntu上运行

gcc concat_test.c -o concat_test

./concat_test

abc + def = def

原始字符串= def

在OS X中编译并运行Xcode

abc + def = abcdef

原始字符串= abcdef

  1. 为什么这适用于Mac而不是Ubuntu?
  2. 它应该在Ubuntu上运行吗?
  3. 它应该在Mac上运行吗?
  4. 我可以发誓它曾经在Ubuntu工作直到最近,但我不知道会有什么改变让它停止工作?
  5. 编译器设置是否与此工作有关?

chq*_*lie 5

您的代码调用未定义的行为,因为您将目标缓冲区作为snprintf()格式的源字符串之一传递.这不受支持:

7.21.6.5 snprintf功能

概要

#include <stdio.h>

int snprintf(char * restrict s, size_t n,
             const char * restrict format, ...);
Run Code Online (Sandbox Code Playgroud)

描述

该snprintf函数等效于fprintf,除了输出被写入数组(由参数指定s)而不是流.如果n为零,则不写入任何内容,并且s可能是空指针.否则,n-1丢弃st 之外的输出字符而不是写入数组,并在实际写入数组的字符末尾写入空字符.如果在重叠的对象之间进行复制,则行为未定义.

(强调我的).

snprintfUbuntu(glibc)和OS/X(Apple libc,基于BSD源)之间的实现有所不同.行为不同,不能依赖,因为它在所有情况下都是未定义的.

你可以这样实现safe_strcat():

#include <string.h>

char *safe_strcat(char *dest, size_t size, const char *src) {
    char *p = memchr(dest, '\0', size);
    if (p != NULL) {
        strncat(p, src, size - (p - dest) - 1);
    }
    return dest;
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 不要叫这个功能safe_strncat(),它确实是一个安全的版本strcat().
  • 在目标指针本身之后传递目标数组的大小,而不是在源指针之后.
  • 返回目标指针不允许调用者检测截断.如果目标数组足够大,你可以返回结果的长度,例如snprintf(),你仍然不会告诉调用者在调用之前目标是否为空终止(for safe_strcat和safe_strncat).

您可以将相同的模型用于安全版本strcpy,strncat并且strncpy(但不实现strncpy()反直觉语义):

char *safe_strcpy(char *dest, size_t size, const char *src) {
    if (size > 0) {
        *dest = '\0';
        strncat(dest, src, size - 1);
    }
    return dest;
}

char *safe_strncat(char *dest, size_t size, const char *src, size_t n) {
    char *p = memchr(dest, '\0', size);
    if (p != NULL) {
        if (n > size - (p - dest) - 1)
            n = size - (p - dest) - 1;
        strncat(p, src, n);
    }
    return dest;
}

char *safe_strncpy(char *dest, size_t size, const char *src, size_t n) {
    if (size > 0) {
        if (n > size - 1)
            n = size - 1;
        *dest = '\0';
        strncat(dest, src, n);
    }
    return dest;
}
Run Code Online (Sandbox Code Playgroud)