我在GDB在线调试器中编写了以下代码:
#include <stdio.h>
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进行编译。代码已编译,但即使存在目录中提供名称的文件,我也没有得到任何输出消息。
答案 0 :(得分:3)
作为answered by Yunnosch,您可能忘记检查fopen(3)的失败。一个更好的习惯是始终检查,至少通过编码:
fp = fopen("abc.txt","r");
if (fp == NULL) { perror("fopen abc.txt"); exit(EXIT_FAILURE); };
并养成至少在任何地方做的习惯。使用perror(3)(或strerror(3)和errno(3))是一个很有用的习惯,因为你想要一些与失败相关的理由(由errno
给出或许通过{{1} })。
更一般地,始终阅读您正在使用的功能的文档(对于标准功能,至少在某些reference网站上,以及可能在C11标准中n1570 ),并且负责处理他们的失败(至少,通过检查失败并退出并向perror
发送有用的消息);对于Unix函数,请参阅他们的stderr
页面(在Linux上,从intro(2)和intro(3)开始;对于Solaris,从intro(2)&amp; intro(3)开始..) 。在您的Unix终端中,还可以尝试man
...对于POSIX标准,请启动here。
是什么让我感到兴奋的是没有我试图在屏幕上打印的消息。
这很简单。 stdout 是缓冲的(另请参阅setvbuf(3)),并且通常是行缓冲的。因此,不以man fopen
结尾的printf
的输出仍然在缓冲区内,而不在屏幕上。获取的习惯几乎总是用换行符结束printf(3)控件格式字符串,否则使用fflush(3)显式刷新缓冲区。
对于新手,几乎没有理由避免使用明确的\n
来结束printf
。所以改用
\n
否则,请在程序中经常调用printf("jkjkkjkj\n");
。顺便说一句,出于这些缓冲原因,fflush(NULL);
应该在调用system(3),fork(2),execve(2)和其他重要的程序范围函数之前完成。
优化了写在行no
附近
这可能发生在C standard library本身(例如,来自某些fflush(NULL)
的{{1}}),这通常不会使用调试信息进行编译。在实践中,请相信您的C标准库:您更有可能在getc
中的代码中出现错误。
您应该编译自己的源代码with libc.so
(要求GCC编译器以DWARF格式提供所有警告和调试信息,{{1}在using the gdb
debugger之前,您需要改进代码以完全不收到任何警告。
请注意undefined behavior,花几个小时阅读UB,并成为UB的scared。
答案 1 :(得分:1)
尝试在fp
中防止NULL,并且为了更好的衡量,请确保打印调试输出(如Some Programmer Dude的评论)。
#include <stdio.h>
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执行)只能关闭成功打开的内容。