我写了一个小程序来检查我的内存中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: 如果要求您在没有填充的情况下有效地使用内存,那么唯一的方法是创建一个特殊的内存分配器吗?或者是否可以禁用填充?
答案 0 :(得分:6)
你有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字节形式存储它们,则需要2个cpu周期来检索int c
并进行一些位移以获得c的实际值正确对齐用作int。
答案 1 :(得分:6)
让我们看看你的输出是否打印了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(1)的重复调用以“双字”增量返回地址,但我不会指望它。
我的代码是在x86 32位机器上运行的。其他机器可能略有不同,有些编译器可能会以不同的方式进行优化,但这些想法应该成立。
答案 2 :(得分:5)
变量本身不占用4个字节的内存,它占用1个字节,然后是3个字节的填充,因为堆栈上的下一个变量是int,因此必须是字对齐的。
在类似下面的情况下,您会发现变量anotherChar
的地址比b
的地址大1个字节。然后在int c
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;
}
答案 3 :(得分:2)
我假设它与堆栈中变量的打包有关。我相信你的例子是强制整数为4字节对齐。因此,在char变量之前(或之后)需要3个字节的填充(取决于我想的编译器)。
答案 4 :(得分:1)
回答问题的最后部分:为什么不使用4个字节作为char?
为什么不为char[1000000]
使用400万字节?
答案 5 :(得分:0)
这是由于对齐限制。字符大小仅为1个字节,但整数与4个字节的倍数对齐。字符也可以跟随其他字符(或简称),这些字符可能具有更宽松的对齐约束。在这些情况下,如果char的大小确实如你所建议的那样是4个字节,那么我们将消耗比所需更多的空间。