发现了分段错误,但之前的消息正在优化
我在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)仅关闭成功打开的内容。