向printf()添加换行符会改变代码的行为

出于某种原因,将\n添加到printf()改变以下代码的行为。 没有\n的代码会打印(null)\n的代码会导致Segmentation fault

Printf.c

 #include <stdio.h> int main(int argc, char* argv[]){ printf("%s", argv[1]); } 

Printf.c – 输出

 $ gcc -o Printf Printf.c $ ./Printf (null) 

Printf_Newline.c

 #include <stdio.h> int main(int argc, char* argv[]){ printf("%s\n", argv[1]); } 

Printf_Newline.c – 输出

 $ gcc -o Printf_Newline Printf_Newline.c $ ./Printf_Newline Segmentation fault (core dumped) 

我很好奇明白这背后的原因。

Solutions Collecting From Web of "向printf()添加换行符会改变代码的行为"

两者都是未定义的行为 ,所以答案可以停在这里。

但是(null)的输出至少有一个解释。 这是glibc (GNU C库)的一个扩展。 在printf()%s传递0在C标准中被认为是未定义的,因此很可能导致崩溃glibc的开发者决定做​​一些有意义的事情。

第二次崩溃的原因是编译器决定优化 :而不是printf("%s\n", argv[1]) ,它执行puts(argv[1]) ,这在语义上是等价的到C标准,因此允许优化。 但glibc s“(null)-trick”只在printf()

程序中还有一个未定义的行为 :您可能会访问argv 越界 。 当i > argc时,不能保证在argv[i]能找到什么值。 argc可能是0的一个小的机会,所以你也可以体验其他任何东西

如果程序没有提供任何命令行参数,代码在这两种情况下都有未定义的行为 ,所以会发生任何事情。

既然你很好奇(对你有好处!),下面是你观察到的一个可能的解释:

  • printf("%s\n", argv[1]); puts(argv[1]);printf("%s", argv[1]); 仍然调用printf()

  • printf一些实现接受一个空指针作为%s转换的参数,因此输出(null)

  • puts()对空指针有未定义的行为,在你的情况下是一个分段错误。

尝试编译两个没有任何优化( -O0 ),看看你是否得到(null)输出有和没有\n

你可以玩godbolt的编译器资源管理器 ,看看clang如何改变-O0的行为,而不是gcc

无参数执行argv[1]应为NULL指针。 用argv[1]NULL

 printf("%s", argv[1]); 

会调用未定义的行为。