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

时间:2011-03-01 04:27:18

标签: c data-structures struct size char

我写了一个小程序来检查我的内存中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: 如果要求您在没有填充的情况下有效地使用内存,那么唯一的方法是创建一个特殊的内存分配器吗?或者是否可以禁用填充?

6 个答案:

答案 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的手册页说“分配大小字节并返回指向已分配内存的指针。”它还说它将“返回指向已分配内存的指针,该指针适用于任何类型的变量”。从我的测试开始,对malloc(1)的重复调用以“双字”增量返回地址,但我不会指望它。

注意事项

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

答案 2 :(得分:5)

变量本身不占用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;
}

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

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