C 为什么printf逐字打印(null)以及到底发生了什么?

C 为什么printf逐字打印(null)以及到底发生了什么?,c,printf,format-specifiers,C,Printf,Format Specifiers,在C编程练习中,我正在做类似的事情(只是简化): 输出是 (null) 这里发生了什么?我假设printf将零解释为char*,那么NULL? 我如何通过类似这样的方式复制这个结果 char string[] = NULL; //compiler-error printf( "%s", string); printf("%s", (char *) 0); ?您也可以使用以下方法执行此操作: char *string = NULL; printf("%s", string); 当传递指向

在C编程练习中,我正在做类似的事情(只是简化):

输出是

(null)
这里发生了什么?我假设
printf
将零解释为
char*
,那么
NULL
? 我如何通过类似这样的方式复制这个结果

char string[] = NULL; //compiler-error
printf( "%s", string);
printf("%s", (char *) 0);

您也可以使用以下方法执行此操作:

char *string = NULL;

printf("%s", string);

当传递指向
%s
null
指针时,
printf()
的许多实现将打印
(null)
或类似内容。但是他们不必这样做(这不是标准所要求的)。

在您的示例中,将0传递给
printf
会导致未定义的行为,因为您使用的格式说明符表示它打印字符串,但您给它一个int。要复制,可以执行以下操作:

char *string = NULL;
printf("%s", string);
首先,你的

printf("%s", 0);
导致未定义的行为(UB)<
printf
中的code>%s需要一个
char*
指针作为参数。您正在传递
0
,这是一个
int
。这已经破坏了你的代码,就像

printf("%s", 42); 
会的。对于特定的UB,
0
为零这一事实没有任何区别

第二,如果您真的想尝试将空端口传递给
%s
格式说明符,您必须执行以下操作

char string[] = NULL; //compiler-error
printf( "%s", string);
printf("%s", (char *) 0);
当然,这也会导致未定义的行为,因为
%s
需要指向有效字符串的指针作为参数,而
(char*)0
不是有效的字符串指针。但有些实现更喜欢优雅地处理这种情况,只需打印
(null)


在您的特定情况下,您很幸运:
printf(“%s”,0)
“工作”的方式与
printf(“%s”,(char*)0)
的工作方式相同,并且您的实现通过输出
(null)

来节省时间,正如其他人所指出的,向
printf%s
传递空指针并不保证做任何事情。在其他条件相同的情况下,当
printf
尝试取消对空指针的引用时,我们可能会出现分段冲突或其他不正常的崩溃。然而,为了方便起见,
printf
的许多(大多数?)实现在其内部深处具有

case 's':
    char *p = va_arg(argp, char *);
    if(p == NULL) p = "(null)";
    fputs(p, stdout);

null//编译器错误
常量定义为大写,C区分大小写。谢谢,我确实键入了“NULL”,只是在这里输入错误…我接受了AnT的答案,因为从技术上讲,它完全回答了我的问题-尽管Greg Hewgill答案中的注释讨论至少有同样的帮助…请不要使用数组,只需更改为
char*string=NULL。我还没试过,但“怀疑”这会(部分)起作用。但我想知道的是:按照你建议的方式进行,我会冒segfault的风险吗,因为不能保证
printf
会遇到终止'\0'-字符?@polymonal\u donut:这与终止'\0'字符无关,因为
NULL
指针根本不指向任何东西。哦,我明白了。。。
(null)
printf
中定义的
null
的字符串解释?@polymonent\u donut:对。打印
(null)
的行为对程序员来说是一种方便,由
printf()
的一些(或大多数)实现提供。这是一种方便,因为打印东西通常比简单地崩溃有用得多。@GregHewgill:另一方面,我可能认为崩溃会更好。当需要指向字符串的指针时,将NULL传递到printf的代码有缺陷。我宁愿尽早抓住那只虫子。程序输出中的杂散
(null)
太容易丢失。这不是打印
(null)
的原因。例如,如果你要通过
5
而不是
0
,它仍然是“寻找字符串,但没有收到”,但结果将与打印
(null)
@Greg截然不同谢谢,我编辑了我的答案。你每天都会学到新东西:)所谓“未定义的行为”,通常指“未定义的标准”,对吗?只是问一下,因为printf源代码以某种方式解释了零指针并打印出
(null)
(因此在printf源代码中,指定了行为,这就是这个注释问题的重点)。是的,未被标准定义,意味着实现(编译器、标准库源代码等)只要标准的措辞没有明确排除,他们可以做他们喜欢做的事情。实际上,由于缺乏保证的结果,UB通常会尖叫“真的不要这样做!”@多项式甜甜圈:如果调用UB,请准备。换言之:一定要避免costs@chux:从非常迂腐的角度来看,
%s
需要一个指向字符串开头的指针。字符串是C语言中的一个正式术语,在7.1.1中定义为“由第一个空字符终止并包括该空字符的连续字符序列”。
printf
中的
s
说明符规范不使用术语字符串的原因是,它还必须涵盖
%42s
等不需要空字符终止的情况。但是纯
%s
需要一个空终止符,它允许我们将其参数描述为指向字符串的指针。