使用 %s 调用 printf 并传递零长度的字符*是未定义的行为吗?
Is it undefined behavior to call printf with %s and pass a zero-length char*?
以下代码中的第三行是否定义良好?
char* result = new char[0];
printf("%dn", strlen(result));
printf("%sn", result);
delete[] result;
当我运行代码时,我得到预期的输出(长度为 0,后跟打印的两个换行符(。但是,我对这是否是一个明确定义的行为或我只是幸运没有信心。
对三线的呼叫是否定义明确?
简短回答:这是未定义的行为
长答案:在C++中,分配大小0
数组将生成指向没有元素的数组的有效指针。 从标准(取自这个答案(:
从 5.3.4/7
当直接新声明符中的表达式值为零时,将调用分配函数来分配没有元素的数组。
从 3.7.3.1/2
取消引用作为零大小请求返回的指针的效果是未定义的。
(强调我的(
这意味着无法正确读取(或写入(从new T[0]
请求返回的指针。
字符串格式"%s
"的strlen
和printf
都被定义为处理以特殊NUL
字符结尾的字符串。它们需要从提供的指针读取字符序列,以尝试找到此NUL
字符才能正常运行(这会导致 UB,因为这需要取消引用指针(。这些行为在 C 标准中定义,因为C++标准将大多数 C 库类型/函数的定义委托回 C 标准。
%s
printf
访问权限定义为执行以下操作:
来自 C11 标准 §7.21.6.1/6
如果不存在 l 长度修饰符,则参数应是指向字符类型数组的初始元素的指针。
数组中的字符将写入(但不包括(终止空字符。如果指定了精度,则写入的字节数不超过该字节数。如果未指定精度或大于数组大小,则数组应包含空字符。
这需要访问数组(这将是 UB,因为指针对取消引用无效(
奖金
由于使用了strlen
,您的示例代码实际上是在第二行引入 UB,原因与上述类似。
strlen
定义为执行以下操作:
来自 C11 标准 §7.24.6.3/3:strlen
函数
返回
strlen 函数返回终止空字符前面的字符数。
这是 UB,原因与使用printf
相同。
很抱歉回答了您的"原始"问题(在您编辑之前(:
C呢?
在 C 中,您没有new
.
然而:
strlen
对数组中的字符进行计数,直到找到NUL
字符。
printf(%s)
将打印数组中的字符,直到找到NUL
个字符。
如果您有本机编译器并且数组不包含NUL
字符,则这两个命令将在数组结束后继续搜索NUL
字符。
例:
char a[6]="Hello ";
char b[100]="world!";
char c[100]="John!";
printf("%sn",a);
如果编译器将数组b
放在数组之后的内存中,则a
此示例将打印"Hello world!
但是,如果编译器决定在a
之后放置c
,程序将打印"Hello John!
如果使用可以检测数组外部访问的编译器(例如 .NET 的C++编译器(,则当到达数组末尾并且没有NUL
字符或数组末尾甚至会被视为NUL
字符时,您将收到错误。
总而言之,你可以说:根据编译器的不同,当你将数组传递给printf(%s)
时,当它不包含NUL
字符时,你会有不同的行为。
这就是我所说的未定义行为...
我不知道C++中的new char[0]
如何表现,但我认为与 C 没有区别......
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 未定义的引用在哪里
- 编译时的 CImg 库返回对"__imp_SetDIBitsToDevice"的未定义引用
- 对Py_Initialize()的未定义引用
- c++11评估顺序(未定义的行为)
- 使用 %s 调用 printf 并传递零长度的字符*是未定义的行为吗?
- 对 'i2c_smbus_read_word_data(int, 无符号字符)的未定义引用
- 读取文件内容时未定义的字符,文件末尾没有换行符
- 将 (*abc) + 15 未定义,因为数组只有 10 个字符长
- 在C++中,返回从本地字符数组创建的字符串是否会导致内存泄漏或未定义的行为
- C++ [链接器错误] 未定义对"执行计算(字符,双精度)"的引用
- 使用 iostream 读取和签名字符时未定义的行为
- 在c++中调用函数时未定义的符号添加随机字符
- 通过无符号整数读取无符号字符数组未定义,因此不安全
- 帮助未定义和多个字符成为常量