(sizeof)char 始终在32位GCC编译器中返回 1 。
但由于32位编译器的基本块大小为4,当基本大小为4字节时,char如何占用单个字节???
考虑以下因素:
struct st
{
int a;
char c;
};
sizeof(st)返回为8 与默认块大小4字节一致(因为分配了2个块)
我永远无法理解为什么 sizeof(char)在分配大小为4的块时返回为1 。
有人可以解释这个???
我会非常感谢任何回复解释!!!
编辑:'bits'的拼写错误已更改为'bytes'。我对第一次编辑的人抱歉。我回滚了编辑,因为我没有注意到你做的改变。 感谢所有那些明确表示必须改变的人,特别是@Mike Burton为了解决这个问题,以及@jalf,他似乎对我对概念的理解得出结论!!
答案 0 :(得分:23)
sizeof(char)
总是1.永远。您所谈论的“块大小”只是机器的本机字大小 - 通常是导致最有效操作的大小。您的计算机仍然可以单独处理每个字节 - 这就是sizeof
运算符告诉您的内容。执行sizeof(int)
时,它会返回4,告诉您计算机上int
为4个字节。同样,您的结构长度为8个字节。 sizeof
中没有关于字节中有多少位的信息。
你的结构长8个字节而不是5个(正如你所料)的原因是编译器正在将 padding 添加到结构中,以便使所有内容与本机字长保持良好对齐,再次提高效率。大多数编译器为您提供打包结构的选项,可以使用#pragma
指令或其他编译器扩展,在这种情况下,您可以强制您的结构采用最小尺寸,无论您的机器是什么字长。
char
的大小为1,因为这是您的计算机可以处理的最小访问大小 - 对于大多数计算机而言是8位值。 sizeof
运算符为您提供所有其他数量的大小,单位为char
个对象的大小与您询问的大小相同。出于性能原因,编译器会将 padding (请参阅下面的链接)添加到您的数据结构中,因此它在实践中比您在查看结构定义时想象的要大。
有一篇名为Data structure alignment的维基百科文章有很好的解释和例子。
答案 1 :(得分:8)
是结构对齐。 c
使用1个字节,未使用3个字节。更多here(带图片!)
答案 2 :(得分:6)
演示结构对齐的示例代码:
struct st
{
int a;
char c;
};
struct stb
{
int a;
char c;
char d;
char e;
char f;
};
struct stc
{
int a;
char c;
char d;
char e;
char f;
char g;
};
std::cout<<sizeof(st) << std::endl; //8
std::cout<<sizeof(stb) << std::endl; //8
std::cout<<sizeof(stc) << std::endl; //12
struct
的大小大于其各个组件的总和,因为它被32位编译器设置为可被4个字节整除。这些结果可能在不同的编译器上有所不同,特别是如果它们位于64位编译器上。
答案 3 :(得分:3)
首先,sizeof
返回多个字节,而不是位。 sizeof(char) == 1
告诉您char
长度为8位(一个字节)。 C中的所有基本数据类型至少有一个字节长。
您的结构返回大小8.这是三件事的总和:int
的大小,char
的大小(我们知道1
),以及编译器添加到结构中的任何额外填充的大小。由于许多实现使用4字节int
,这意味着您的编译器正在为您的结构添加3个字节的填充。最有可能是在char
之后添加,以使结构的大小为4的倍数(32位块中32位CPU访问数据最有效,32位是4字节)。 / p>
编辑:仅因为块大小为四个字节并不意味着数据类型不能小于四个字节。当CPU将一个字节char
加载到32位寄存器中时,该值将自动(由硬件)进行符号扩展,以使其填充寄存器。 CPU足够智能,可以以N字节为增量处理数据(其中N是2的幂),只要它不大于寄存器即可。将数据存储在磁盘或内存中时,没有理由将每个char
存储为四个字节。您的结构中的char
看起来好像是四个字节长,因为它后面添加了填充。如果您将结构更改为两个 char
变量而不是一个,您应该看到结构的大小相同(您添加了额外的数据字节,并添加了编译器)少一个填充字节。)
答案 4 :(得分:2)
C和C ++中的所有对象大小都是根据 bytes 定义的,而不是 bits 。字节是计算机上最小的可寻址内存单位。一位是一个二进制数字,0
或1
。
在大多数计算机上,一个字节是8位(因此一个字节可以存储0到256之间的值),尽管计算机存在其他字节大小。
内存地址标识字节,即使在32位计算机上也是如此。地址N和N + 1指向两个后续字节。
int
,通常为32位,覆盖4个字节,这意味着存在4个不同的内存地址,每个内存都指向int
的一部分。
在32位机器中,所有 32 实际上意味着CPU设计为使用32位值有效工作,并且地址长度为32位。这并不意味着只能以32位的块来寻址存储器。
CPU仍然可以处理单个字节,例如,在处理char
时非常有用。
至于你的例子:
struct st
{
int a;
char c;
};
sizeof(st)
返回8不是因为所有结构都有一个可被4整除的大小,而是因为 alignment 。为了使CPU有效地读取整数,它必须位于可被整数(4字节)整除的地址上。因此,int
可以放在地址8,12或16上,但不能放在地址11上。
char
只要求其地址可以被char
(1)的大小整除,因此可以将其放在任何地址上。
所以理论上,编译器可以给你的结构大小为5个字节......除非你创建了一个st
个对象的数组,否则这个不行。< / p>
在一个数组中,每个对象都紧跟在前一个对象之后,没有填充。因此,如果数组中的第一个对象放置在可被4整除的地址,那么下一个对象将放置在高于5字节的地址处,这将不可被4整除,因此第二个对象将被整除数组中的struct无法正确对齐。
要解决此问题,编译器会在结构中插入填充,因此其大小将成为其对齐要求的倍数。
不是因为不可能创建大小不是4的倍数的对象,而是因为st
结构的一个成员需要4字节对齐,所以每次都是编译器在内存中放置int
,它必须确保它被放置在可被4整除的地址。
如果你创建了两个char
的结构,它的大小不会达到4.它通常会得到2的大小,因为当它只包含char
时,该对象可以放在任何地址,因此对齐不是问题。
答案 5 :(得分:1)
Sizeof以字节为单位返回值。你在谈论比特。 32位架构是字对齐和字节引用。架构如何存储char是无关紧要的,但对于编译器,您必须一次引用1个字节的字符,即使它们使用的字节少于1个字节。
这就是sizeof(char)为1的原因。
整数是32位,因此sizeof(int)= 4,双精度是64位,因此sizeof(double)= 8等。
答案 6 :(得分:1)
由于优化填充被添加,因此对象的大小为 1,2或n * 4字节(或类似的东西,谈论x86)。这就是为什么添加填充到5字节对象和1字节没有。单char
不需要填充,可以在1个字节上分配,我们可以将它存储在分配有malloc(1)
的空间中。 st
无法存储在malloc(5)
分配的空间中,因为正在复制st
结构时,正在复制整个8个字节。
答案 7 :(得分:0)
它的工作方式与使用半张纸相同。您将一个部分用于char,另一部分用于其他部分。编译器将隐藏此信息,因为将字符加载和存储到32位处理器寄存器取决于处理器。
有些处理器只有加载和存储32位部分的指令,其他处理器必须使用二进制操作来提取char的值。
对char进行寻址是因为AFAIR定义为最小的可寻址内存。在32位系统上,指向两个不同整数的指针将至少相隔4个地址点,而char地址只相隔1个。