有些人可以解释一下,下面的例子确实有什么问题,尤其是带有&#34的部分,这可能会导致从不是4的倍数的地址加载32位无符号长整数" :
"编译器通常会自然地阻止对齐问题 对齐所有数据类型。事实上,对齐问题通常不是 内核开发人员的主要担忧是gcc人们不得不担心 关于他们。然而,当程序员也玩的时候会出现问题 密切关注指针并访问环境外的数据 由编译器预期。
使用较大对齐的重铸指针访问对齐的地址 地址导致对齐问题(无论这可能意味着什么 特殊的架构)。也就是说,这是个坏消息:
char dog[10]; char *p = &dog[1]; unsigned long l = *(unsigned long *)p;
此示例将指向char的指针视为指向unsigned的指针 long,这可能导致从32位无符号长度加载 地址不是四的倍数。
如果您正在思考,"当我在世界上时,我会这样做吗?"你是 可能是对的。然而,它已经出现了,它将再次出现 小心。现实世界的例子可能不那么明显。"
虽然我不能真正理解这个问题,但是可以通过使用以下代码来解决吗?如果是,为什么?
char * dog = (char *)malloc(10 * sizeof(char));
char *p = dog +1;
unsigned long l = *(unsigned long*)p;
答案 0 :(得分:1)
您提出的解决方案与引用的解决方案几乎相同,因此它遇到了同样的问题。
错位问题。
当您保留内存时,编译器会使用自动变量(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);
答案 1 :(得分:0)
你引用的那段话是完全正确的。
大多数情况下,你不必担心对齐,因为编译器会为你处理它,并且这很有效,除非你做一些如此松散的事情,你成功地挫败了编译器试图保护你。
当您致电malloc
时,没有问题,因为malloc
是特殊的(以多种方式)。除此之外,它还保证返回一个指向适合任何类型对象的存储指针。"
char dog[] = "My dog Spot";
char *p = &dog[0];
unsigned long l = *(unsigned long *)p;
假设阵列碰巧在内存中布局如下:
+---+---+---+---+
100: | | | M | y |
+---+---+---+---+
104: | | d | o | g |
+---+---+---+---+
108: | | S | p | o |
+---+---+---+---+
112: | t |\0 | | |
+---+---+---+---+
也就是说,假设数组dog
最终在内存地址102处,而不是4的倍数。因此指针p
也指向地址102,我们尝试访问{{1在地址102处。(您注意到我已将其更改为long int
,而不是原始示例中的&dog[0]
,以试图让事情更加清晰。)
所以我们可能期望变量&dog[1]
最终包含1299783780或1679849805(即0x4d792064或0x6420794d),因为它们是前四个字节的表示"我的d"以big-endian或little-endian表示解释。
但由于它是一个不对齐的访问权限,我们可能不会得到任何数字;该程序可能会崩溃,例如"总线错误"代替。
如果我们受到约束并决定做这种事情,我们可以设法自己做这样的调整,用这样的事情:
l
当然,将指针移动char dog[] = "My dog Spot";
char *p = dog;
int al = (intptr_t)p % sizeof(unsigned long);
al = sizeof(unsigned long) - al;
if(al == sizeof(unsigned long)) al = 0;
p += al;
unsigned long l = *(unsigned long *)p;
直到它指向4的正确倍数,它并没有指向"我的d"更多;现在它指向"狗"
我做过一两次这样的事情,但我无法推荐它。