C避免对齐问题 [英] C Avoiding Alignment Issues

查看:201
本文介绍了C避免对齐问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请有些人解释一下,下面的示例到底有什么问题,特别是带有可能导致从非4的倍数的地址装入32位无符号长整数的部分":

编译器通常会自然地防止对齐问题 对齐所有数据类型.实际上,对齐问题通常不是 内核开发人员的主要顾虑gcc人们必须担心 关于他们.但是,当程序员也玩游戏时,就会出现问题 与指针紧密联系并访问环境外部的数据 编译器预期的.

使用更大对齐的重定位指针访问对齐的地址 地址会导致对齐问题(无论这可能意味着 特定的体系结构).也就是说,这是个坏消息:

char dog[10];
char *p = &dog[1];
unsigned long l = *(unsigned long *)p;

此示例将指向char的指针视为指向未签名的指针 long,这可能会导致从中加载32位无符号long 地址不是四的倍数.

如果您在想,我什么时候会这样做?"你是 可能是正确的.然而,它已经出现了,并且还会再次出现,所以 小心.现实世界中的例子可能并不那么明显."

尽管我不太了解这个问题,但是可以使用以下代码解决它吗?如果可以,为什么?

char * dog = (char *)malloc(10 * sizeof(char));
char *p = dog +1;
unsigned long l = *(unsigned long*)p;

解决方案

您提出的解决方案与引用的解决方案几乎相同,因此存在相同的问题.

错位问题

当您保留内存时,编译器将按照要求的对齐方式保留它,或者使用自动变量(char dog[10]),或者使用malloc ed变量.

当您通过执行指针算术技巧(如您正在执行的技巧)来愚弄编译器时,则它不能保证访问对齐正确.

为什么会出现问题?

因为,根据所使用的硬件体系结构,编译器可能会发出要求2或4字节对齐的指令. 例如,ARM有几条指令,要求数据以2字节对齐(也就是说,其地址必须为偶数). 因此,为ARM处理器构建的代码可能会发出访问冲突.

那您将如何解决您的问题?

通常使用memcpy:

char *dog = malloc(10 * sizeof(char));
char *p = dog;
unsigned long l;

memcpy(&l, p+1, sizeof(l));
//You can use l safely now.

//Copy back l to the array:
memcpy(p+1, &l, sizeof(l));

Could some please explain, what is really wrong with the following example, especially the part with "which might result in the 32-bit unsigned long being loaded from an address that is not a multiple of four":

"The compiler generally prevents alignment issues by naturally aligning all data types. In fact, alignment issues are normally not major concerns of the kernel developersthe gcc folks have to worry about them. Issues arise, however, when the programmer plays too closely with pointers and accesses data outside the environment anticipated by the compiler.

Accessing an aligned address with a recast pointer of a larger-aligned address causes an alignment issue (whatever that might mean for a particular architecture). That is, this is bad news:

char dog[10];
char *p = &dog[1];
unsigned long l = *(unsigned long *)p;

This example treats the pointer to a char as a pointer to an unsigned long, which might result in the 32-bit unsigned long being loaded from an address that is not a multiple of four.

If you are thinking, "When in the world would I do this?" you are probably right. Nevertheless, it has come up, and it will again, so be careful. The real-world examples might not be so obvious."

Though I don't really understand the problem, can it be solved by using the following code and if so, why?

char * dog = (char *)malloc(10 * sizeof(char));
char *p = dog +1;
unsigned long l = *(unsigned long*)p;

解决方案

Your proposed solution is pretty much the same as the quoted one, so it suffers from the same problem.

Misalignment problem

When you reserve memory, the compiler reserves it with the required alignment, either with the usage of automatic variables (char dog[10]), either with malloced variables.

When you fool the compiler by doing pointer arithmetic tricks, like the one you are doing, then it cannot guarantee that access alignment will be correct.

Why is this problematic?

Because, depending on the hardware architecture you are using, the compiler may emit instructions that require 2 or 4 byte alignment. For instance, ARM has several instructions that require data to be 2 byte aligned (this is, its address has to be even). Thus, your code built for an ARM processor would likely to emit an access violation.

How would you solve your problem then?

Usually, with a memcpy:

char *dog = malloc(10 * sizeof(char));
char *p = dog;
unsigned long l;

memcpy(&l, p+1, sizeof(l));
//You can use l safely now.

//Copy back l to the array:
memcpy(p+1, &l, sizeof(l));

这篇关于C避免对齐问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆