正如许多年轻的程序员所做的那样,我了解到在代码中的不同点插入大量“here1”、“here2”等打印到控制台语句的有用性,以找出我的程序何时出错。在我的计算机科学学习过程中,这种强力调试技术已经拯救了我很多很多次。然而,当我开始用 C 语言编程时,我偶然发现了一个有趣的问题。如果我尝试跑步

void* test;

printf("hello world");
test[5] = 234;

当然,由于没有为 testChar 分配内存,我遇到了段错误。但是,您可能会从逻辑上认为“hello world”会在 seg 错误发生之前打印,因为这是代码的流程,但根据我的经验,总是先发生 seg 错误,然后“hello world” " 根本不会打印到控制台。(我无法测试这个确切的例子,但我在 Linux 机器上使用 gcc 多次遇到过这种情况。)我猜这与编译器重新排列一些东西和/或 printf 有关使用某种异步刷新的缓冲区,因此不是立即刷新的。这完全是我的猜测,因为我真的不知道为什么会发生这种情况。在我使用过的任何其他语言中,无论“testChar = ...”行引起什么问题,仍然会打印“hello world”,因此我可以确定问题出在哪里。

我的问题是为什么当我用 C 编程时会发生这种情况?为什么不先打印 hello world?其次,是否有比这更好的 C 编程调试技术可以完成相同的基本任务?比如,有一种简单/直观的方法来找到有问题的代码行吗?

编辑:我无意中给出了一个工作示例哈哈。我现在所拥有的应该会导致段错误。有趣的是,通常当我 想要一个段错误,我就得到一个,现在当我真正想要一个时,我写了合法的代码!

有帮助吗?

解决方案

您发布的代码完全合法,不会导致段错误 - 不需要 malloc 任何东西。您的问题一定出在其他地方 - 请发布导致问题的最小代码示例。

编辑: 您现在已将代码编辑为具有完全不同的含义。尽管如此,未显示“hello world”的原因是输出缓冲区尚未刷新。尝试添加

fflush( stdout );

在 printf 之后。

关于查找问题的根源,您有以下几种选择:

  • 使用以下命令在代码中随意散布 printfs __FILE____LINE__ C 宏
  • 学习使用调试器 - 如果您的平台支持核心转储,您可以使用核心映像来查找错误所在。

其他提示

printf 写入已缓冲的 stdout。有时,在程序崩溃之前该缓冲区不会被刷新,因此您永远看不到输出。有两种方法可以避免这种情况:

  1. 使用 fprintf( stderr, "error string" ); 因为 stderr 没有缓冲。
  2. 添加一个呼叫 fflush( stdout ); 在 printf 调用之后。

正如尼尔和其他人所说,编写的代码很好。也就是说,直到您开始修改缓冲区 testChar 指着。

“作为,一个简单的/直观的方式来找到的代码这是一个问题行?”

使用GDB(或任何其他调试器)。

要找到你的程序赛格故障您-g选项编译(包括调试符号)从运行应用程序的 GDB 后,它将停止在赛格故障。

您可以再看看回溯与bt命令来查看,此时你得到了赛格故障。

示例:

> gdb ./x
(gdb) r
Starting program: /proj/cpp/arr/x 
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000019a9 in willfail () at main.cpp:22
22          *a = 3;
(gdb) bt
#0  0x000019a9 in willfail () at main.cpp:22
#1  0x00001e32 in main () at main.cpp:49
(gdb) 

的输出由默认缓冲前的输出被实际写入stdout发生段错误。尝试:

fprintf(stderr, "hello, world\n");

(错误是由默认无缓冲。)

此代码不应该段错误。你只是分配一个指针,指向一个字符串的指针变量。如果你是例如事情会有所不同使用strcpy与无效指针复制的东西。

没有出现可能是由于缓冲的I / O消息。打印换行符\n或拨打fflush到刷新输出缓冲区。

您有两个问题。第一个是你的(原)代码不会出现段错误。这是完全有效的分配该字符串常量一个字符指针。但是,让我们现在就离开这一边并假装你已经把东西那里的的段错误。

然后,它通常是缓冲器的问题,一种在C运行时库和一个在操作系统本身。你需要刷新他们。

要做到这一点是(在UNIX,不完全肯定有关Linux中的fsync,但你要保证,除非系统本身出现故障导向这个最终会发生),最简单的方法:

printf ("DEBUG point 72\n"); fflush (stdout); fsync (fileno (stdout));

我在UNIX常常这样做,它可以确保C运行时库刷新到UNIX(fflush)和UNIX缓冲器sync'ed到磁盘(fsync),有用的,如果stdout不是终端设备或你正在做它为一个不同的文件句柄。

void* test;

printf("hello world");
test[5] = 234;

及其可能的“hello world”正在由系统缓冲某处,而不是立即打印到屏幕上。其存储的等待对于任何进程/线程机会/不管是负责书写屏可以有机会来处理它。虽然它的等待(可能还有其他数据缓冲输出)你是功能整理。它配备了非法访问和段错误。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top