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

时间:2018-05-05 11:35:40

标签: c segmentation-fault printf

我在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进行编译。代码已编译,但即使存在目录中提供名称的文件,我也没有得到任何输出消息。

2 个答案:

答案 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执行)只能关闭成功打开的内容。