当前位置: 首页 > 面试题库 >

使用printf的%s说明符打印NULL的行为是什么?

白丁雨
2023-03-14
问题内容

遇到一个有趣的面试问题:

test 1:
printf("test %s\n", NULL);
printf("test %s\n", NULL);

prints:
test (null)
test (null)

test 2:
printf("%s\n", NULL);
printf("%s\n", NULL);
prints
Segmentation fault (core dumped)

尽管这在某些系统上可能运行良好,但至少我的系统出现了分段错误。对此行为的最佳解释是什么?上面的代码在C中。

以下是我的gcc信息:

deep@deep:~$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

问题答案:

首先,第一件事printf是:期望其%s参数使用有效的(即非NULL)指针,因此将NULL正式传递给它是不确定的。它可能会显示“(null)”,也可能会删除硬盘上的所有文件-
就ANSI而言,这是正确的行为(至少,这是Harbison和Steele告诉我的。)

话虽这么说,是的,这确实是奇怪的行为。事实证明,发生的事情是当您执行以下简单操作时printf

printf("%s\n", NULL);

GCC是( 啊哈 )足够聪明,解构到一个呼叫此 puts。第一个printf,这个:

printf("test %s\n", NULL);

非常复杂,以至于gcc会发出对real的调用 printf

(注意,gcc printf在编译时会发出有关无效参数的警告。这是因为它很早以前就已经开发出了解析*printf格式字符串的功能。)

您可以自己编译该-save-temps选项,然后查看生成的.s文件,从而自己查看。

当我编译第一个示例时,我得到:

movl    $.LC0, %eax
movl    $0, %esi
movq    %rax, %rdi
movl    $0, %eax
call    printf      ; <-- Actually calls printf!

(评论由我添加。)

但是第二个产生了以下代码

movl    $0, %edi    ; Stores NULL in the puts argument list
call    puts        ; Calls puts

奇怪的是它不会打印以下换行符。好像已经弄清楚这将导致段错误,所以它不会打扰。(它有它-当我编译它时警告我。)



 类似资料:
  • 由于ANSI C99,通过有或。但是bool是否也有格式说明符? 它将打印:

  • 有人能解释一下printf中的是如何使用说明符“%g”的吗?下面的输出让我很困惑: 我了解到使用最短的表示形式。 但是下面的输出仍然让我困惑 我的问题是:为什么能给出确切的数字,而不能? 似乎16个有效数字是准确的。有人能告诉我原因吗?

  • 有了,我可以使用表示

  • 在 C (n1570 7.21.6.1/10) 和 C(通过包含 C 标准库)中,向类型与其转换规范不匹配的 printf 提供参数是未定义的行为。一个简单的例子: 格式字符串指定 int,而参数是浮点类型。 这个问题的灵感来自一个用户的问题,他遇到了大量转换不匹配的遗留代码,这显然没有伤害,参见。理论和实践中的未定义行为。 最初,仅仅声明格式不匹配的UB似乎很激烈。很明显,输出可能是错误的,这取

  • 在我正在读的一本书里,写着带有单个参数(没有转换说明符)的< code>printf被弃用。它建议替换为 与 或者 有人能告诉我为什么是错的吗?书上写着它包含漏洞,这些漏洞是什么?

  • 假设我有以下功能: 我希望调用者指定要打印的浮点数,以及小数点后的位数。(由<代码>表示)。%d说明符) 然而,在编译此代码时,我收到两个警告: 和 我的问题是:如何将格式说明符(例如本例中的)注入现有格式说明符?