为什么printf字面打印(null)以及究竟发生了什么?

pol*_*nut 5 c printf format-specifiers

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

printf( "%s", 0);
Run Code Online (Sandbox Code Playgroud)

输出是

(null)
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?我假设printf将零解释为a char *,那么NULL?我怎么能用这样的东西复制这个结果

char string[] = NULL; //compiler-error
printf( "%s", string);
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 6

首先,你的

printf("%s", 0);
Run Code Online (Sandbox Code Playgroud)

导致未定义的行为(UB).%sin printf需要char *指针作为参数.你在路过0,这是一个int.仅这一点已经破坏了你的代码,就像

printf("%s", 42); 
Run Code Online (Sandbox Code Playgroud)

将.对于具体的UB的事实,0是一个没有任何区别.

其次,如果你真的想尝试将null-ponter传递给%s格式说明符,你必须做类似的事情

printf("%s", (char *) 0);
Run Code Online (Sandbox Code Playgroud)

当然,这也会导致未定义的行为,因为%s需要指向有效字符串的指针作为参数,并且(char *) 0不是有效的字符串指针.但有些实现更喜欢优雅地处理这种情况并且只是打印(null).

在你的特殊情况下,你很幸运:printf("%s", 0)"工作"的方式printf("%s", (char *) 0)和你的实现一样,你的实现通过输出节省了一天(null).

  • 通过"未定义的行为",通常意味着"标准未定义"对吗?只是问一下,因为printf-source以某种方式解释了零指针并打印出`(null)`(所以在printf-source中,指定了行为,这就是这个注释问题的重点). (2认同)
  • 是的,标准未定义,意味着实现(编译器,标准库源等)可以做他们喜欢的事情,只要它没有被标准的措辞明确排除. (2认同)
  • 在实践中,由于缺乏保证的结果,UB通常会尖叫"真的不要这样做!" (2认同)
  • @polynomial_donut:如果调用UB,请准备[鼻恶魔](http://www.catb.org/jargon/html/N/nasal-demons.html)。换句话说:**不惜一切代价避免** (2认同)
  • @chux:形成非常迂腐的观点,`%s`需要一个指向*string*开头的指针.*String*是7.1.1中定义的C中的正式术语,是"由第一个空字符终止并包括第一个空字符的连续字符序列".`printf`中`s`说明符的规范不使用术语*string*的原因是它还必须覆盖`%42s`这样的情况,它们不需要空字符终止.但纯`%s`需要一个空终止符,它允许我们将其参数描述为指向*string*的指针. (2认同)