C问题:为什么char实际占用内存中的4个字节?

我写了一个小程序来检查我的内存中char占用了多少字节,它显示char实际占用内存中的4个字节。 我理解这主要是因为字对齐并且没有看到char只有1个字节的优点。 为什么不使用4个字节的char?

int main(void) { int a; char b; int c; a = 0; b = 'b'; c = 1; printf("%p\n",&a); printf("%p\n",&b); printf("%p\n",&c); return 0; } 

输出:0x7fff91a15c58 0x7fff91a15c5f 0x7fff91a15c54

更新:我不相信malloc只会为char分配1个字节,即使sizeof(char)作为参数传递,因为malloc包含一个标题将确保标题是字对齐的。 任何意见?

Update2:如果要求你有效地使用没有填充的内存,唯一的方法是创建一个特殊的内存分配器? 或者是否可以禁用填充?

你有int,char,int

请参阅“为什么限制字节对齐?”下的图像。 http://www.eventhelix.com/realtimemantra/ByteAlignmentAndOrdering.htm

  Byte 0 Byte 1 Byte 2 Byte 3 0x1000 0x1004 X0 X1 X2 X3 0x1008 0x100C Y0 Y1 Y2 

如果它以4字节,1字节和4字节的forms存储它们,它将需要2个cpu周期来检索int c和一些位移以使c的实际值正​​确对齐以用作int。

对准

让我们看看你输出的打印a,b和c的地址:

输出:0x7fff91a15c58 0x7fff91a15c5f 0x7fff91a15c54

请注意,b不在同一个4字节边界上? 那a和c是彼此相邻的吗? 这是它在内存中的样子,每行占用4个字节,最右边的列占第0位:

 | b | x | x | x | 0x5c5c ----------------- | a | a | a | a | 0x5c58 ----------------- | c | c | c | c | 0x5c54 

这是优化空间和保持字对齐的编译器方式。 即使你的b地址是0x5c5f,它实际上并没有占用4个字节。 如果您使用相同的代码并添加短d,您将看到:

 | b | x | d | d | 0x5c5c ----------------- | a | a | a | a | 0x5c58 ----------------- | c | c | c | c | 0x5c54 

其中d的地址是0x5c5c。 短路将与两个字节对齐,因此在c和d之间仍然会有一个未使用的内存字节。 添加另一个字符,您将获得:

 | b | e | d | d | 0x5c5c ----------------- | a | a | a | a | 0x5c58 ----------------- | c | c | c | c | 0x5c54 

这是我的代码和输出。 请注意,我的地址会略有不同,但这是我们真正关心的地址中最不重要的数字:

 int main(void) { int a; char b; int c; short d; char e; a = 0; b = 'b'; c = 1; printf("%p\n",&a); printf("%p\n",&b); printf("%p\n",&c); printf("%p\n",&d); printf("%p\n",&e); return 0; } $ ./a.out 0xbfa0bde8 0xbfa0bdef 0xbfa0bde4 0xbfa0bdec 0xbfa0bdee 

的malloc

malloc的手册页说它“ 分配大小字节并返回指向已分配内存的指针 ”。 它还说它将“ 返回指向已分配内存的指针,该内存适合任何类型的变量 ”。 从我的测试开始,对malloc(1)的重复调用以“双字”增量返回地址,但我不会指望这一点。

注意事项

我的代码是在x86 32位机器上运行的。 其他机器可能略有不同,有些编译器可能会以不同方式进行优化,但这些想法应该成立。

变量本身不占用4个字节的内存,它占用1个字节,然后是3个字节的填充,因为堆栈上的下一个变量是一个int,因此必须是字对齐的。

在类似下面的情况下,您会发现变量anotherChar的地址比b的地址大1个字节。 然后在int c之前跟随2个字节的填充

 int main(void) { int a; char b; char anotherChar; int c; a = 0; b = 'b'; c = 1; printf("%p\n",&a); printf("%p\n",&b); printf("%p\n",&anotherChar); printf("%p\n",&c); return 0; } 

我假设它与堆栈中变量的打包有关。 我相信你的例子是强制整数为4字节对齐。 因此,在char变量之前(或之后)需要3个字节的填充(取决于我想的编译器)。

回答问题的最后部分:为什么不使用4个字节的char?

为什么不使用400万字节的char[1000000]

这是由于对齐限制。 字符大小仅为1个字节,但整数与4个字节的倍数对齐。 字符也可以跟随其他字符(或简称),这些字符可能具有更宽松的对齐约束。 在这些情况下,如果char的大小确实如你所建议的那样是4个字节,那么我们将消耗比所需更多的空间。