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

Why does printf literally print (null) and what exactly happens?

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

printf( "%s", 0);

输出为

(null)

这里发生了什么?我假设 printf 将零解释为 char *,所以 NULL? 我怎样才能通过类似

的方式复制这个结果
char string[] = NULL; //compiler-error
printf( "%s", string);

?

您也可以使用类似的方式执行此操作:

char *string = NULL;

printf("%s", string);

许多 printf() 的实现在将 NULL 指针传递给 %s 时将打印 (null) 或类似内容。但他们不必这样做(标准没有要求)。

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

char *string = NULL;
printf("%s", string);

首先,你的

printf("%s", 0);

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

printf("%s", 42); 

会。对于那个特定的 UB,0 的事实没有任何区别。

其次,如果您真的想尝试将空指针传递给 %s 格式说明符,则必须执行类似

的操作
printf("%s", (char *) 0);

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

在您的特定情况下,您很幸运:printf("%s", 0) "worked" 与 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);