c-堆栈上的数据对齐方式是什么



我读K&R C(2(185p,其中一部分很难理解。

尽管机器各不相同,但每台机器都有一个限制性最强的类型:如果限制性最强类型可以存储在特定地址,那么所有其他类型也可以。在某些机器上,最严格的类型是;在其他情况下,intlong就足够了。

我认为
大多数现代计算机都是字节可寻址的(通过wiki(。最小的数据类型char足以容纳任何堆栈区域。所以所有的数据类型都适用于任意的堆栈位置。但为什么会有这样的限制

在这个类似的问题中,

CPU通常要求(或者如果(某些类型的数据存储在某个值的倍数(2的幂(的地址,则工作效率更高。

这解释了我的问题。但我无法理解。这是否意味着堆栈中某些二次方(2,4,8,16,…,1024,2048,…(的地址需要某些类型
如果是,为什么?或者,如果我错了,它指的是什么?

对齐数据有两个原因:

  • 硬件要求。某些机器只有在正确对齐的情况下才能访问内存中的数据。当然,您可以执行多次读取,并使用一些位算术来模拟从任何地址读取,但这将对性能造成破坏
  • 性能。即使一台机器可以访问任何地址的任何数据,如果数据正确对齐,它的性能可能会更好

当然,这可能因机器而异,但";适当地对齐";通常意味着N位数据的地址可以被N/8整除。

因此,在对齐很重要的机器上,32位的int将被放置在可被4整除的存储器地址,64位的指针将被放置于可被8整除的存储地址,等等

你可以在结构中看到这一点。

#include <stdint.h>
#include <stdio.h>
typedef struct {
uint32_t u32;
void*    p;
uint8_t  u8;
} Struct;
int main(void) {
Struct s;
printf("%pn", (void*)&s.u32);
printf("%pn", (void*)&s.p);
printf("%pn", (void*)&s.u8);
printf("%pn", (void*)(&s+1));
printf("0x%zxn", sizeof(s));
}
$ gcc -Wall -Wextra -pedantic a.c -o a && ./a
0x7ffef5f775d0
0x7ffef5f775d8
0x7ffef5f775e0
0x7ffef5f775e8
0x18

这意味着我们有这个:

0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7
+-------+-------+---------------+-+-------------+ 
| u32   |XXXXXXX| p             |*|XXXXXXXXXXXXX|   * = u8 
+-------+-------+---------------+-+-------------+   X = unused

注意u32p之间浪费的空间。因此p正确对齐。

还要注意u8之后的浪费空间。这样,当你有一个它们的数组时,结构本身就会正确对齐。如果没有这个最后的填充,数组的第二个元素的u32p将不会正确对齐。

最后,请注意,使用

typedef struct {
uint32_t u32;
uint8_t  u8;
void*    p;
} Struct;

会导致更小的结构。

0 1 2 3 4 5 6 7 8 9 a b c d e f 
+-------+-+-----+---------------+
| u32   |*|XXXXX| p             |   * = u8 
+-------+-+-----+---------------+   X = unused

最新更新