使用%p
转换说明符打印空指针是否为未定义的行为?
#include <stdio.h>
int main(void) {
void *p = NULL;
printf("%p", p);
return 0;
}
这个问题适用于C标准,而不是C实现.
使用%p
转换说明符打印空指针是否为未定义的行为?
#include <stdio.h>
int main(void) {
void *p = NULL;
printf("%p", p);
return 0;
}
这个问题适用于C标准,而不是C实现.
This is one of those weird corner cases where we're subject to the limitations of the English language and inconsistent structure in the standard. So at best, I can make a compelling counter-argument, as it's impossible to 100 it :)1
问题中的代码表现出明确的行为.
[7.1.4]是问题的基础,让我们从这里开始:
除非在下面的详细描述中另有明确说明,否则以下语句均适用:如果函数的参数具有无效值(such as a值位于函数域之外,或指针位于程序的地址空间之外,or a null pointer、[... other examples ...])[...],则行为未定义.[... other statements ...]
这是一种笨拙的语言.一种解释是,列表中的项目是所有库函数的UB,除非被单独的描述覆盖.但是这个列表以"比如"开头,表明它是说明性的,而不是详尽的.例如,它没有提到字符串的正确空终止(对于例如strcpy
的行为至关重要).
因此,很明显,7.1.4的意图/范围只是"无效值"导致UB(unless stated otherwise).我们必须查看每个函数的描述,以确定什么是"无效值".
strcpy
[7.21.2.3]只说:
strcpy
函数将s2
指向的字符串(包括终止空字符)复制到s1
指向的数组中.如果在重叠的对象之间进行复制,则行为未定义.
它没有明确提到空指针,也没有提到空终止符.取而代之的是,从"s2
指向的字符串"推断,唯一有效的值是字符串(即指向以NULL结尾的字符数组的指针).
事实上,这种模式可以在个人描述中看到.其他一些例子:
[7.6.4.1 (fenv)]将当前浮点环境存储在object pointed to乘以
envp
[7.12.6.4 (frexp)]将整数存储在整数object pointed to乘
exp
中
[7.19.5.1 (fclose)]乘stream pointed to乘
stream
printf
[7.19.6.1]表示大约%p
:
p
-参数应为指向void
的指针.指针的值以实现定义的方式转换为打印字符序列.
NULL是一个有效的指针值,本节没有明确提到NULL是一种特殊情况,也没有明确说明指针必须指向对象.因此,它是被定义的行为.
1.除非标准作者站出来,或者除非我们能找到类似于rationale文档的东西来澄清问题