Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用snprintf避免缓冲区溢出_C_Printf - Fatal编程技术网

C 使用snprintf避免缓冲区溢出

C 使用snprintf避免缓冲区溢出,c,printf,C,Printf,我这样使用snprintf来避免缓冲区溢出: char err_msg[32] = {0}; snprintf(err_msg, sizeof(err_msg) - 1, "[ ST_ENGINE_FAILED ]"); 我添加了-1,以便在字符串长度超过32字节时为空终止符保留空间 我的想法正确吗 站台: 通用条款4.4.1 C99 sizeof将返回数据类型在内存中使用的字节数,而不是字符串的长度。例如,sizeof(int)在32位系统上返回'4'字节(好吧,我想这取决于实现)。由于您

我这样使用
snprintf
来避免缓冲区溢出:

char err_msg[32] = {0};
snprintf(err_msg, sizeof(err_msg) - 1, "[ ST_ENGINE_FAILED ]");
我添加了
-1
,以便在字符串长度超过32字节时为空终止符保留空间

我的想法正确吗

站台:

  • 通用条款4.4.1
  • C99

sizeof将返回数据类型在内存中使用的字节数,而不是字符串的长度。例如,sizeof(int)在32位系统上返回'4'字节(好吧,我想这取决于实现)。由于您在数组中使用了一个常量,您可以很高兴地将其传递给printf。

您不需要-1,因为引用中指出:

函数snprintf()和 vsnprintf()写入的内容不能超过 大小字节(包括尾随字节) “\0”)

注意“包括尾随“\0”部分,请参见:

函数
snprintf()
vsnprintf()
的写入长度不超过
size
字节(包括尾部的
'\0'


不需要-1。C99
snprintf
始终为零终止。Size参数指定输出缓冲区的大小,包括零终止符。因此,代码就变成了

char err_msg[32];
int ret = snprintf(err_msg, sizeof err_msg, "[ ST_ENGINE_FAILED ]");
ret
包含实际打印的字符数(不包括零终止符)


但是,请不要与Microsoft的(C99之前版本)混淆,后者不会执行notnull终止,因此具有完全不同的行为(例如,如果缓冲区不够大,则返回
-1
,而不是将要打印的长度)。如果使用
\u snprintf
,您应该使用与问题中相同的代码。

正如其他人所说,在这种情况下,您不需要-1。如果数组是固定大小的,我将使用
strncpy
。它是为复制字符串而设计的-
sprintf
是为进行困难的格式化而设计的。但是,如果数组的大小未知,或者您试图确定格式化字符串需要多少存储空间。这就是我真正喜欢的标准指定版本的
snprintf

char* get_error_message(char const *msg) {
    size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
    char  *buffer = malloc(needed+1);
    sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
    return buffer;
}

将此功能与
va_copy
结合使用,可以创建非常安全的格式化字符串操作

对于给定的示例,您应该这样做:

char err_msg[32];
strncpy(err_msg, "[ ST_ENGINE_FAILED ]", sizeof(err_msg));
err_msg[sizeof(err_msg) - 1] = '\0';
或者更好:

char err_msg[32] = "[ ST_ENGINE_FAILED ]";

他正在将
sizeof
应用于目标数组,这是完全正确的。32是正确的。在这种情况下,他不想要字符串的大小(由strlen给出),他想要
err\u msg
缓冲区容量(以保证它不会写超过其结尾)。旁注:GCC不支持C99:但是,您知道,在一个现代环境中,gcc和标准库组合不包括
snprintf
?当我一两年前使用MinGW时,它实际上称为Microsoft的
\u snprintf()
,它的行为与标准的
snprintf()
不同(我认为它并不总是nul终止字符串)。不要使用strncpy()如果字符串太大,无法放入目标中;strncpy()不为null,如果复制的内容太长,则终止它。此外,它总是复制N个字符,即使源是1字节,目标是1兆字节。@Jonathan:no。虽然strncpy没有以\0结尾是正确的,但如果它在源字符串中找到字符串终止符,它会停止。对于固定长度的缓冲区,我通常使用
strncpy(dest,src,sizeof(dest));dest[sizeof(dest)-1]='\0'
保证了空终止,比
snprintf
麻烦少,更不用说很多人使用
snprintf(dest,sizeof(dest),src)sprintf(buffer,
,因为您已经保留了大小完全正确的
buffer
。这将避免此错误。正如在对另一个答案的评论中所指出的:如果字符串可能太大而无法放入目标,请不要使用strncpy();strncpy()如果复制的内容太长,则不使用null终止。此外,它始终复制N个字符,即使源是1字节,目标是1兆字节。@Jonathan Leffler,您对多少字节
strncpy()
的描述不正确。“最多复制N个字节的src。”我已经调整了示例以修复空终止。@anacrolix:您的示例不保证空终止。它保证
strncpy()
永远不会覆盖缓冲区中的最后一个字符。您必须显式执行
err\u msg[sizeof(err\u msg)-1]='\0';
才能获得终止。