你引用的这段话完全正确。
大多数时候,您不必担心对齐问题,因为编译器会为您处理它,并且效果很好,除非您做了一些奇怪的事情,以至于成功挫败了编译器保护您的尝试。
你打电话时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,我们尝试访问long int
地址 102。(你会注意到我已将其更改为&dog[0]
,相对于&dog[1]
在最初的例子中,试图让事情变得更清楚。)
所以我们可能期望变量l
最终包含 1299783780 或 1679849805 (即 0x4d792064 或 0x6420794d),因为这些是以大端或小端表示解释的前四个字节“My d”的表示。
但由于这是一次未对齐的访问,我们可能不会得到任何一个数字;该程序可能会因“总线错误”之类的问题而崩溃。
如果我们有义务并决心做这种事情,我们可以自己设法进行对齐,如下所示:
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;
当然,移动指针后p
直到它指向 4 的正确倍数为止,它不再指向“My d”;现在它指向“狗”。
我曾经做过一两次这样的事情,但我真的不能推荐它。