发现了分段错误,但之前的消息正在优化

我在GDB在线调试器中编写了以下代码:

#include  int main() { printf("jkjkkjkj"); int p , n; FILE *fp; printf("jkjkkjkj2"); fp = fopen("abc.txt","r"); while ( (n = getc(fp))!= EOF) { printf( "the chareacter here is %d \n", n); } n = fclose(fp); return 0; } 

在执行代码时,我正在尝试从文件中获取字符的行中出现分段错误。 我知道由于文件不存在,分段错误错误即将来临。

然而,令我感兴趣的是没有我试图在屏幕上打印的消息。 我尝试检查调试器,一旦找到:

 optimized out written near the line no 

但是,我尝试将getchar()置于此处,即使分段故障仍然存在,消息也会打印在屏幕上。

怎么解释这个? 为什么会这样? 当我将getchar()放在不同的地方时,为什么要打印消息?

我曾尝试在Solaris服务器上编写此代码并使用GCC进行编译。 代码已编译,但即使存在目录中提供的名称的文件,我也没有得到任何输出消息。

正如Yunnosch所回答的 ,你可能忘了检查fopen(3)的失败。 一个更好的习惯是始终检查,至少通过编码:

  fp = fopen("abc.txt","r"); if (fp == NULL) { perror("fopen abc.txt"); exit(EXIT_FAILURE); }; 

并养成至少在任何地方做的习惯。 使用perror(3) (或使用errno(3)的 strerror(3) )是一个很有用的习惯,因为你想要一些与失败相关的原因(由errno或者通过perror )。

更一般地,总是阅读您正在使用的function的文档 (对于标准function,至少在某些参考网站上,可能在C11标准n1570中 ),并注意处理它们的故障 (至少,通过检查失败并退出并向stderr发送有用信息); 对于Unix函数,请参阅他们的man页(在Linux上,从intro(2)和intro(3)开始;对于Solaris,从intro(2)和intro(3)开始 ..)。 在您的Unix终端中,请尝试man fopen …对于POSIX标准,从这里开始。


令我感兴趣的是没有我试图在屏幕上打印的消息。

这很简单。 stdout是缓冲的(参见setvbuf(3) ),并且通常是行缓冲的。 因此,一个不以\n结尾的printf的输出仍然在缓冲区内,而且还没有在屏幕上。 获取的习惯是几乎总是用换行符结束printf(3)控件格式字符串,否则使用fflush(3)显式刷新缓冲区。

对于新手来说,几乎没有理由避免使用明确的\n结束你的printf 。 所以请改用

 printf("jkjkkjkj\n"); 

否则,调用fflush(NULL); 经常在你的程序中。 顺便说一下,出于这些缓冲的原因,应该在调用system(3) , fork(2) , execve(2)和其他重要的程序范围函数之前完成fflush(NULL)


优化写出附近的行号

这可能发生在C标准库本身(例如,来自某些libc.so getc ),它通常不会使用调试信息进行编译。 在实践中,相信您的C标准库:您更有可能在libc中的代码中存在错误。

您应该使用 gcc -Wall -Wextra -g编译您自己的源代码(要求GCC编译器以DWARF格式提供所有警告和调试信息, gdb调试器可以使用)并且您需要改进代码以完全不发出警告在使用gdb调试器之前。

注意未定义的行为 ,花几个小时阅读UB,并害怕 UB。

尝试防止fp中的NULL,并且为了好的措施,确保打印调试输出(如Some Programmer Dude的评论)。

 #include  int main(void) { int p , n; FILE *fp; printf("jkjkkjkj2\n"); fp = fopen("abc.txt","r"); if (NULL != fp) { while ( (n = getc(fp))!= EOF) { printf( "the chareacter here is %d \n", n); } n = fclose(fp); } else { printf("File opening failed somehow!\n"); } return 0; } 

注意好的触摸(由Basile Starynkevitch)仅关闭成功打开的内容。