假设导致总线错误的代码块执行正常

A block of code that is suppose to cause a bus error executes fine

我目前正在阅读 Expert C Programmign - Deep C Secrets。在作者解释 Bus Error 和 Segmentation fault 的第 164 页,他展示了这行代码

union { 
  char a[10];
  int i;
} u ;

int * p = ( int * ) &(u.a[1]);
*p = 17; /* the misaligned addr in p causes a bus error */

上面的代码假设会触发总线错误,但是当我 运行 它时,它 运行 没有任何错误。作者给出了以下解释

This causes a bus error because the array/int union ensures that character array "a" is also at a reasonably aligned address for an integer, so "a+1" is definitely not. We then try to store 4 bytes into an address that is aligned only for single-byte access. A good compiler will warn about misalignment, but it cannot spot all occurrences.

我对上述陈述的理解是,char 是 1 个字节,我们试图在 char a[10] 的索引上放置一个 4 字节的 int 因此总线会报错(不知道我的理解对不对)

我的问题是为什么上面的代码没有导致总线错误。

注意:我不是学计算机的,简单的解释一下会有帮助。

注意: 已经有人提出了一个看起来与此问题相似的问题,但仅针对上述代码块。

我认为这本书有误。该代码导致未定义的行为。因此,期望它的任何特定行为都是有缺陷的。另请注意,并非所有架构都会导致总线错误。如果这本书没有解释这个事实,那也不代表它。

My understanding of the above statement is that , char is 1 byte and we are trying to place an int which is 4 byte on an index of char a[10] hence a bus error will occur ( am not sure if my understanding is right or wrong )

问题不在于 charint 的大小,而是它们的对齐方式。通常,体系结构对您从中加载 data/code 的地址很挑剔,例如,您可能只能从 16 位的倍数的地址加载 16 位整数,或者函数必须始终从4 字节边界。

如果您不遵守这一点,处理器可能会读取错误的数据或以异常的方式惩罚您。 OS 然后可以使用多个对齐访问来模拟它,或者将它作为 SIGBUS 传递给用户应用程序。后者是作者在他的设置中可能遇到的情况。

这一切与 C 有什么关系?

你所拥有的是未定义的行为。处理器、内存控制器、编译器、OS 和您附近的鼻腔恶魔产卵的相互作用都会影响它产生的效果(如果有的话)。在您的计算机上,处理器可能本身就支持未对齐访问,所以它可以工作,但它仍然是您不能依赖的东西:它只是 undefined。 (特别是在优化方面,这些东西可能会反咬一口。Works for me™ 不足以编写定义明确的 C 代码!)

您尝试获取的数据跨越 32 位边界,因此需要 2 次内存获取(但编译器在编译时不一定知道这一点)。

注:这本书很老了,说的是32位CPUs。对于 64 位,您可能必须将 int * p = ( int * ) &(u.a[1]); 更改为 int * p = ( int * ) &(u.a[5]);,这样就无法从对齐地址的一次内存提取中获取所需的所有数据。

出于向后兼容性的原因,大多数 Intel CPUs(以及 AMD 等衍生产品)在指令级别自动处理内存对齐错误,因此您不会注意到任何错误(简单地说,它会自动添加额外的读取锁定总线以确保读取之间没有任何变化)。

在许多其他 CPU 架构(ARM、PowerPC、MIPS、较新的 Intel 架构)上,示例代码可能会导致所描述的问题,但现在某些操作系统,例如 Linux,可以配置为自动捕获故障并执行 "fixup" 允许程序继续运行而不知道存在问题。对于大多数程序,这可能不会被用户注意到,但非常耗时,并且会在实时软件和驱动程序中引起实际问题。

时间关键代码通常根据其编译所针对的 CPU 体系结构进行条件编译以执行或不执行未对齐访问。在 linux 中,伪文件“/proc/cpu/alignment”可用于控制内核行为并查看有关 "fixups".

数量的统计信息