这个结构的大小是如何变成 4 字节的
我确实有一个包含位字段的结构。根据我的说法,它是 2 个字节,但结果是 4 个字节。我已经在 stackoverflow 上阅读了一些与此相关的问题,但无法与我的问题相关。这是我确实拥有的结构
struct s{
char b;
int c:8;
};
int main()
{
printf("sizeof struct s = %d bytes \n",sizeof(struct s));
return 0;
}
,如果 int 类型必须位于其内存边界上,那么输出应该是 8 个字节,但它显示 4 个字节?
I do have a structure having bit-fields in it.Its comes out to be 2 bytes according to me but its coming out to be 4 .I have read some question related to this here on stackoverflow but not able to relate to my problem.This is structure i do have
struct s{
char b;
int c:8;
};
int main()
{
printf("sizeof struct s = %d bytes \n",sizeof(struct s));
return 0;
}
if int type has to be on its memory boundary,then output should be 8 bytes but its showing 4 bytes??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
来源:http://geeksforgeeks.org/?p=9705
总之:它正在优化位的打包(这就是位字段的用途)在不影响对齐的情况下尽可能最大化。
变量的数据对齐涉及数据存储在这些存储体中的方式。例如,int在32位机器上的自然对齐是4个字节。当数据类型自然对齐时,CPU 会以最少的读取周期获取它。
同样,
short int
的自然对齐是 2 个字节。这意味着,一个短整型可以存储在bank 0 –bank 1对或bank 2 –bank 3对中。double
需要 8 个字节,并占用存储体中的两行。双精度的任何未对齐都会强制两个以上的读取周期来获取双精度数据。请注意,双精度变量将在 32 位机器上分配在 8 字节边界上,并且需要两个内存读取周期。在 64 位机器上,根据存储体数量,双精度变量将分配在 8 字节边界上,并且只需要一个内存读取周期。
因此编译器会对每个结构体引入对齐要求。它将作为结构中最大的成员。如果您从
struct
中删除char
,您仍将获得 4 个字节。在您的
struct
中,char
是 1 字节对齐的。它后面是一个int
位字段,它是 4 字节对齐的整数,但您定义了一个位字段。8 位 = 1 字节。
Char
可以是任何字节边界。所以Char
+Int:8
= 2 个字节。嗯,这是一个奇数字节边界,因此编译器添加了额外的 2 个字节来维持 4 字节边界。要使其为 8 个字节,您必须声明一个实际的
int
(4 个字节)和一个char
(1 个字节)。那是 5 个字节。嗯,这是另一个奇数字节边界,因此struct
被填充为 8 字节。我过去控制填充的常用做法是在我的
struct
之间放置填充符,以始终保持 4 字节边界。因此,如果我有一个像这样的struct
:我将按如下方式插入分配:
这将为我提供一个大小为 4 个字节 + 1 个字节 + 3 个字节的
struct
= 8 字节!这样我就可以确保我的struct
按照我想要的方式填充,特别是当我通过网络将其传输到某个地方时。另外,如果我改变了我的实现(例如,如果我可能将此struct
保存到二进制文件中,填充符从一开始就在那里,所以只要我保持了最初的结构,一切都很好!)最后,您可以在 带位字段的 C 结构大小以获取更多说明。
Source: http://geeksforgeeks.org/?p=9705
In sum: it is optimizing the packing of bits (that's what bit-fields are meant for) as maximum as possible without compromising on alignment.
A variable’s data alignment deals with the way the data stored in these banks. For example, the natural alignment of int on 32-bit machine is 4 bytes. When a data type is naturally aligned, the CPU fetches it in minimum read cycles.
Similarly, the natural alignment of
short int
is 2 bytes. It means, a short int can be stored in bank 0 – bank 1 pair or bank 2 – bank 3 pair. Adouble
requires 8 bytes, and occupies two rows in the memory banks. Any misalignment of double will force more than two read cycles to fetch double data.Note that a double variable will be allocated on 8 byte boundary on 32 bit machine and requires two memory read cycles. On a 64 bit machine, based on number of banks, double variable will be allocated on 8 byte boundary and requires only one memory read cycle.
So the compiler will introduce alignment requirement to every structure. It will be as that of the largest member of the structure. If you remove
char
from yourstruct
, you will still get 4 bytes.In your
struct
,char
is 1 byte aligned. It is followed by anint
bit-field, which is 4 byte aligned for integers, but you defined a bit-field.8 bits = 1 byte.
Char
can be any byte boundary. SoChar
+Int:8
= 2 bytes. Well, that's an odd byte boundary so the compiler adds an additional 2 bytes to maintain the 4-byte boundary.For it to be 8 bytes, you would have to declare an actual
int
(4 bytes) and achar
(1 byte). That's 5 bytes. Well that's another odd byte boundary, so thestruct
is padded to 8 bytes.What I have commonly done in the past to control the padding is to place fillers in between my
struct
to always maintain the 4 byte boundary. So if I have astruct
like this:I am going to insert allocation as follows:
That would give me a
struct
with a size of 4 bytes + 1 byte + 3 bytes = 8 bytes! This way I can ensure that mystruct
is padded the way I want it, especially if I transmit it somewhere over the network. Also, if I ever change my implementation (such as if I were to maybe save thisstruct
into a binary file, the fillers were there from the beginning and so as long as I maintain my initial structure, all is well!)Finally, you can read this post on C Structure size with bit-fields for more explanation.
int c:8;
表示您正在声明一个大小为 8 位的位域
。由于 32 位系统上的alignemt 通常为 4 个字节(=32 位),因此您的对象将显示为 4 个字节而不是 2 个字节(char + 8 位)。int c:8;
means that you are declaring abit-field
with the size of 8 bits. Since the alignemt on 32 bit systems is normally 4 bytes (=32 bits) your object will appear to have 4 bytes instead of 2 bytes (char + 8 bit).但如果你指定
c
应该占用8位,那么它就不是真正的int了,不是吗?c
+b
的大小为 2 个字节,但编译器将结构填充为 4 个字节。But if you specify that
c
should occupy 8 bits, it's not really an int, is it? The size ofc
+b
is 2 bytes, but your compiler pads the struct to 4 bytes.结构体中字段的对齐方式取决于编译器/平台。
也许您的编译器对长度小于或等于 16 位的位域使用 16 位整数,也许它永远不会在小于 4 字节边界的任何内容上对齐结构。
底线:如果您想了解结构体字段如何对齐,您应该阅读您正在使用的编译器和平台的文档。
They alignment of fields in a struct is compiler/platform dependent.
Maybe your compiler uses 16-bit integers for bitfields less than or equal to 16 bits in length, maybe it never aligns structs on anything smaller than a 4-byte boundary.
Bottom line: If you want to know how struct fields are aligned you should read the documentation for the compiler and platform you are using.
在通用的、平台无关的 C 语言中,您永远无法知道结构体/联合体的大小,也无法知道位域的大小。编译器可以在结构/联合/位字段内的任何位置自由添加任意数量的填充字节,除了第一个内存位置。
此外,编译器还可以自由地向位域添加任意数量的填充位,并且可以将它们放置在任何它喜欢的地方,因为哪个位是 msb 和 lsb 不是由 C 定义的
。说到位域,你会被 C 语言冷落,因为它们没有标准。您必须详细阅读编译器文档以了解它们在您的特定平台上的行为方式,并且它们是完全不可移植的。
明智的解决方案是永远不要使用位字段,它们是 C 的冗余功能。相反,请使用按位运算符。按位运算符和深入记录的位字段将生成相同的机器代码(未记录的位字段可以自由地生成相当任意的代码)。但按位运算符保证在世界上任何编译器/系统上都能以相同的方式工作。
In generic, platform-independent C, you can never know the size of a struct/union nor the size of a bit-field. The compiler is free to add as many padding bytes as it likes anywhere inside the struct/union/bit-field, except at the very first memory location.
In addition, the compiler is also free to add any number of padding bits to a bit-field, and may put them anywhere it likes, because which bit is msb and lsb is not defined by C.
When it comes to bit-fields, you are left out in the cold by the C language, there is no standard for them. You must read compiler documentation in detail to know how they will behave on your specific platform, and they are completely non-portable.
The sensible solution is to never ever use bit fields, they are a reduntant feature of C. Instead, use bit-wise operators. Bit-wise operators and in-depth documented bit-fields will generate the same machine code (non-documented bit-fields are free to result in quite arbitrary code). But bit-wise operators are guaranteed to work the same on any compiler/system in the world.