欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C 总线错误 (bus error) - 段错误 (segmentation fault)

程序员文章站 2022-07-13 23:17:04
...

C 总线错误 (bus error) - 段错误 (segmentation fault)

两个常见的运行时错误

  • bus error (core dumped) - 总线错误 (信息已转储)
  • segmentation fault (core dumped) - 段错误 (信息已转储)

错误信息对引起这两种错误的源代码错误并没有作简单的解释,上面的信息并未提供如何从代码中寻找错误的线索,而且两者之间的区别也并不是十分清楚,时至今日依然如此。

错误就是操作系统所检测到的异常,而这个异常是尽可能地以操作系统方便的原则来报告的。总线错误和段错误的准确原因在不同的操作系统版本上各不相同。这里所描述是运行于 SPARC 架构的 SunOS 出现的这两类错误以及产生错误的原因。

当硬件告诉操作系统一个有问题的内存引用时,就会出现这两种错误。操作系统通过向出错的进程发送一个信号与之交流。信号就是一种事件通知或一个软件中断,在 UNIX 系统编程中使用很广,但在应用程序编程中几乎不使用。在缺省情况下,进程在收到总线错误段错误信号后将进行信息转储并终止。不过可以为这些信号设置一个信号处理程序 (signal handler),用于修改进程的缺省反应。

信号是由于硬件中断而产生的。对中断的编程是非常困难的,因为它们是异步发生的 (其发生时间是不可预测的)。阅读信号的主文档和头文件 usr/include/sys/signal.h

1. 在 PC 上捕捉信号

信号处理函数是 ANSI C 的一部分,与 UNIX 一样,它也同样适用于 PC。例如 PC 程序员可以使用 signal() 函数来捕捉 Ctrl-Break 信号,防止用户用这种方法中断程序。

在任何使用信号的源文件中,都必须在文件前面增加一行 #include <singal.h>

这条信息的 core dumped 部分来源于很早的过去,那时所有的内存都是由铁氧化物圆环 (也就是 core,指磁心) 制造的。半导体成为内存的主要制造材料的时间已经超过十五年,但 core 这个词仍然被用作内存的同义词。

core [kɔː(r)]:n. 核心,要点,果心,磁心 vt. 挖...的核

2. 总线错误 (bus error)

事实上,总线错误几乎都是由于未对齐的读或写引起的。它之所以称为总线错误,是因为出现未对齐的内存访问请求时,被堵塞的组件就是地址总线。对齐 (alignment) 的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。在现代的计算机架构中,尤其是 RISC 架构,都需要数据对齐,因为与任意的对齐有关的额外逻辑会使整个内存系统吏大且更慢。通过迫使每个内存访问局限在一个 Cache 行或一个单独的页面内,可以极大地简化 (并加速) 如 Cache 控制器和内存管理单元这样的硬件。

我们表达“数据项不能跨越页面或 Cache 边界”规则的方法多少有些问接,因为我们用地址对齐这个术语来陈述这个问题,而不是直截了当说是禁止内存跨页访问,但它们说的是同一回事。例如,访问一个 8 字节的 double 数据时,地址只允许是 8 的整数倍。所以一个 double 数据可以存储于地址 24、8008 或 32768,但不能存储于地址 1006 (因为它无法被 8 整除)。页和 Cache 的大小是经过精心设计的,这样只要遵守对齐规则就可以保证一个原子数据项不会跨越一个页或 Cache 块的边界。

2.1 引起总线错误的程序

//============================================================================
// Name        : main
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <stdio.h>

int main(int argc, char *argv[])
{
	union union_name
	{
		char a[10];
		int i;
	} union_object;

	printf("argc = %d\n", argc);

	for (int idx = 0; idx < argc; ++idx)
	{
		printf("argv[%d] --> %s\n", idx, argv[idx]);
	}

	printf("argv[argc] = %p\n\n", (void*)argv[argc]);

	int *pt = (int *)&(union_object.a[1]);
	int *pi = (int *)&(union_object.i);

	*pt = 17;

	printf("*pt = %d\n", *pt);
	printf("pt = %p\n", pt);
	printf("pi = %p\n", pi);

	return 0;
}
argc = 1
argv[0] --> D:\visual_studio_workspace\yongqiang\Debug\yongqiang.exe
argv[argc] = 00000000

*pt = 17
pt = 008FFA39
pi = 008FFA38
请按任意键继续. . .

C 总线错误 (bus error) - 段错误 (segmentation fault)

在实际的运行中并没有出现错误,运行环境如下:
C 总线错误 (bus error) - 段错误 (segmentation fault)

相关标签: C - GCC