2

我想测试,如果它是确定访问在C结构的未对齐的成员,请参阅该代码访问未对齐的结构构件

#include <stdio.h> 

#pragma pack(1) /* force 1 byte alignment */ 

/* either member b or member d is mis-aligned */ 
typedef struct 
{ 
    int b; 
    unsigned char c; 
    unsigned int d; 
}A ; 


int main(int argc, char *argv[]) 
{ 
    A _a = {0}; 
    unsigned int *p = NULL; 
    unsigned int *q = NULL; 


    printf("addr of _a : 0x%08x, size of _a : %u\n", &_a, sizeof(_a)); 

    p = (unsigned int*)(&_a.b); 
    q = (unsigned int*)(&_a.d); 

    /* should this fail ? */ 
    (*p)++ , (*q)++; 

    return 0; 

} 

认为程序会崩溃因但是事实证明它工作得很好,已经在Linux 3.6.11(GCC 4.7.2),WinXP(MingW),键盘在线编译器(http://codepad.org/yOoc8ACG

解释结果,我想操作系统已经做了一些事情来保存程序,仍然怀疑它是否适用于VxWorks或其他操作系统

注意:代码在基于Intel的机器上运行!

在此先感谢!

+0

如果你尝试并将p和q传递给另一个函数后会发生什么?或者也许尝试访问这些位置的内存? – 2013-03-13 15:09:22

+1

可能重复[未对齐的内存访问总是会导致总线错误?](http://stackoverflow.com/questions/1496848/does-unaligned-memory-access-always-cause-bus-errors) – ecatmur 2013-03-13 15:10:05

+0

在SPARC上运行。 – WhozCraig 2013-03-13 15:13:19

回答

1

想必您是在英特尔机器上运行。 x86架构可以处理未对齐的访问,而不会有任何问题。不过,您可能在其他体系结构上遇到问题。即使架构碰巧不支持未对齐的访问,但您有时可以通过在某种CPU异常处理程序中使用单字节访问来模拟未对齐的访问,有时操作系统可以为您解决此问题。

我想你也想在测试程序中使用(*p)++(*q)++

+0

是的,你是对的,我应该改为(* p)++和(* q)++ – Tracy 2013-03-13 15:19:12

0

基于x86的体系结构并不常见,因为它们的字访问指令可用于错误对齐的地址。由此产生的操作速度较慢并且不是原子的,但它起作用。

只要您的程序包含#pragma它的含义就(最好)实现定义。一般来说,将数据成员的地址分配给变量unsigned int*将使实现“忘记”它可能会错误对齐,因此它不会为未对齐的加载发出代码。因此,在其重要的体系结构中,*p*q(或两者)都不起作用。

0

结果取决于体系结构和内核配置。通常在x86上,您可以访问未对齐的数据,但会有一些性能损失。这主要是由于与旧系列CPU兼容。

在ARM和SPARC上,行为取决于内核配置。这种未对齐的数据访问可能被操作系统禁止,允许甚至模拟。在后一种情况下,硬件异常会被内核拦截,并在某些操作系统的和平代码中被模拟。

随着编译器版本到位,这变得更加困难。例如,现代GCC生成一个特殊的代码,如果它发现数据没有对齐,就可以以非原子方式访问未对齐的数据(即有几条指令)。

1

上面的一些答案说“因为它是x86,它不会失败”,这是不完全正确的。虽然我知道没有操作系统这样做,但可以配置x86处理器在用户模式下进行非对齐访问时发生故障[不是在内核模式下,但发布的代码看起来像用户模式代码]。但正如我所说的,我知道没有一个操作系统实际上配置了这个位,并且很可能会破坏一些代码,而这些代码并不期望处理器因未对齐的内存访问而出现故障。

无论您如何查看它,未对齐访问的行为都是未定义的,或者最多只能定义实现。这意味着这样一个操作的结果范围从“它的工作方式就像你期望的那样”到了“程序崩溃”的一端。在这个范围的中间可能是“它不会崩溃,但它也没有像你期望的那么完美”的更糟糕的选择 - 例如,你可能会发现你刚刚获得了对应地址的值[较低的内存地址]您希望获取的数据,或者获取确实执行正确,但由于处理器陷入并执行几个步骤的操作,它比对齐的变体长10或100倍,然后从陷阱。如果你还运行多个线程,你也可能会发现变量的更新不是以原子方式完成的,所以你得到的值是“一半一半”,这可能会导致非常奇怪的效果。这并不是一个确定的“事情有点不对,但不是立即明显的方式”的潜在情景的清单。

我的建议是:不要混淆对齐方式,并尽可能绝对不要写代码来访问未对齐的元素。它可能会回来并咬你早晚......