由于某种原因,我不能完全弄清楚我的联合只是结构包含位字段是设置两倍的字节是必要的任何单一的结构。
#include <stdio.h>
#include <stdlib.h>
union instructionSet {
struct Brane{
unsigned int opcode: 4;
unsigned int address: 12;
} brane;
struct Cmp{
unsigned int opcode: 4;
unsigned int blank: 1;
unsigned int rsvd: 3;
unsigned char letter: 8;
} cmp;
struct {
unsigned int rsvd: 16;
} reserved;
};
int main() {
union instructionSet IR;// = (union instructionSet*)calloc(1, 2);
printf("size of union %ld\n", sizeof(union instructionSet));
printf("size of reserved %ld\n", sizeof(IR.reserved));
printf("size of brane %ld\n", sizeof(IR.brane));
printf("size of brane %ld\n", sizeof(IR.cmp));
return 0;
}
所有对sizeof的调用都返回4,但据我所知,它们应该返回2。
4条答案
按热度按时间mepcadol1#
这里有几个问题,首先,你的位域Brane使用的是4字节的unsigned int。
即使只使用了一半的位,也仍然使用了一个完整的32位宽的无符号整型。
第二,Cmp位域使用两种不同的字段类型,所以前3个字段使用32位unsigned int中的8位,然后使用unsigned char,因为它是完整的8位。由于数据对齐规则,该结构至少为6字节,但可能更多。
如果你想优化你的联合体的大小,使其只占用16位,你首先需要使用
unsigned short
,然后你需要总是使用相同的字段类型,以保持所有内容在相同的空间。像这样的事情会完全优化你的工会:
这将给予你一个大小为2周围。
mxg2im7a2#
C 20186.7.2.111允许C实现选择用于位字段的容器的大小:
一个实现可以分配任何足够大的可寻址存储单元来容纳一个位域。如果有足够的空间剩余,则结构中紧接着另一个位域的位域应被打包到同一单元的相邻位中。如果没有足够的空间剩余,则不适合的位域是否被放入下一个单元或与相邻单元重叠由实现定义......
您正在使用的实现显然选择使用四字节单元,这可能也是实现中
int
的大小,表明这是实现的方便大小。ui7jx7zq3#
它没有规定代码的作用,如果没有特定的系统和编译器,就没有意义去推理它。位字段在标准中的规定太差了,以至于不能可靠地用于内存布局之类的事情。
该标准允许编译器为任何位字段类型选择一个“存储单元”,它可以是任何大小。
一种实现可以分配足够大以保持位字段的任何可寻址存储单元。
我们不知道的事:
unsigned int
类型的位域有多大。32位可能有意义,但不能保证。unsigned char
。unsigned char
类型的位域的大小。可以是8到32之间的任何大小。unsigned int
位字段与unsigned char
位字段相遇,会发生什么情况?我们可以知道的事情:
进一步的知识可以通过在头脑中有一个非常具体的系统和编译器来获得。
我们可以使用100%可移植和确定性的按位操作来代替位字段,无论如何都能产生相同的机器码。
vuktfyat4#
了解内存结构填充/内存对齐。默认情况下,32位处理器从内存读取32位(4字节),因为速度更快。因此,在内存中,char + uint 32将写入4 + 4 = 8字节(1字节- char,3字节空间,4字节uint 32)。
把这些行加到程序的开始和结束处,结果就是2。
这是对编译器说的话:将内存对齐到1字节(32位处理器上默认为4)。
PS:使用不同的
#pragma pack
集尝试此示例: