我有一个重复的打印,打印了一堆非空终止的,char*如下所示:
int len1, len2, len3, len4;
char *str1, *str2, *str3, *str4;
get_vals(message, val1, &str1, &len1);
get_vals(message, val2, &str2, &len2);
get_vals(message, val3, &str3, &len3);
get_vals(message, val4, &str4, &len4);
printf("%.*s %.*s %.*s %.*s", len1, str1, len2, str2, len3, str3, len4, str4);
Run Code Online (Sandbox Code Playgroud)
其中将指针get_vals设置char *为内存中的值并将 设置len为文本的长度。传入的值有可能char *被设置为NULL,如果是这样,长度字段将被设置为0。看来这个打印已经发生了很多次并且没有出现段错误,我认为由于长度说明符是0这样的事实,所以可能没有取消引用。然而,这总是安全的吗?也许它与操作系统或 libc 版本相关?是否值得像这样进行安全检查:
printf("%.*s %.*s %.*s %.*s",
len1, str1 ? str1 : "",
len2, str2 ? str2 : "",
len3, str3 ? str3 : "",
len4, str4 ? str4 : "");
Run Code Online (Sandbox Code Playgroud)
当您编写printf("%.*s", len1, str1), 其中len1是零并且str1是空指针时,您正在使用s说明符并将精度设置为 0。我查看了N1570第 7.21.6 节的相关部分。在记录s说明符时,它说:
参数应是指向字符类型数组的初始元素的指针。数组中的字符将写入(但不包括)终止空字符。如果指定了精度,则写入的字节数不会超过该数量。
因此,从技术上讲,只需查看该引用的第一部分,您确实需要提供指向数组的指针,而不是提供空指针。所以你的代码不遵循标准的这一部分。
但是,您将精度设置为 0,因此引用的第二部分告诉我们该printf函数实际上不会将该数组中的任何字符写入输出。对我来说,这意味着它也不会尝试读取任何字符:读取数组末尾之后的内容是不安全的,因此printf实现不应这样做。因此,您的代码可能会在实践中起作用,并且很难想象它会失败的情况。我在实践中能想到的最大问题是静态分析器或验证器可能会抱怨您的代码。