2013-09-21 54 views
1

为什么需要这段代码?使用限制结构尺寸:

typedef struct corr_id_{ 
    unsigned int size:8;  
    unsigned int valueType:8; 
    unsigned int classId:8; 
    unsigned int reserved:8;  

} CorrId; 

我对此做了一些调查,发现这种方式我们将内存消耗限制在我们需要的范围内。 例如

typedef struct corr_id_new{ 
    unsigned int size;  
    unsigned int valueType; 
    unsigned int classId; 
    unsigned int reserved; 

} CorrId_NEW; 

typedef struct corr_id_{ 
    unsigned int size:8;  
    unsigned int valueType:8; 
    unsigned int classId:8; 
    unsigned int reserved:8; 

} CorrId; 

int main(){ 
CorrId_NEW Obj1; 
CorrId  Obj2; 

std::cout<<sizeof(Obj1)<<endl; 
std::cout<<sizeof(Obj2)<<endl; 
} 

输出: -

16 
4 

我想知道这样的场景的实际使用情况?为什么我们不能声明这样的结构,

typedef struct corr_id_new{ 
    unsigned _int8 size;  
    unsigned _int8 valueType; 
    unsigned _int8 classId; 
    unsigned _int8 reserved; 

} CorrId_NEW; 

这是否与编译器优化有关?或者,以这种方式声明结构有什么好处?

+0

实际上你应该结合这两种方法......或者使用'pack' /'packed' –

+2

你确定输出是'4 16'而不是'16 4'吗? –

+0

谢谢。做出了这些改变。 –

回答

1

让我们来看看一个简单的场景,

typedef struct student{ 
    unsigned int age:8; // max 8-bits is enough to store a students's age 255 years 
    unsigned int roll_no:16; //max roll_no can be 2^16, which long enough 
    unsigned int classId:4; //class ID can be 4-bits long (0-15), as per need. 
    unsigned int reserved:4; // reserved 

}; 

上述情况下,所有工作都在只有32位完成。

但是,如果你只使用一个整数,它将采取4 * 32位。

如果我们把年龄定为32位整数,它可以存储在0到2^32的范围内。但是不要忘记,一个正常人的年龄只是最大100或140或150(即使是在这个年龄段学习的人也是如此),需要最多8位存储,所以为什么要浪费剩余的24位。

+0

+20为您的答案.. :) –

1

它常与pragma pack用于创建标签位字段,例如:

#pragma pack(0) 

struct eg { 
    unsigned int one : 4; 
    unsigned int two : 8; 
    unsigned int three : 16 
}; 

可投不管出于什么目的来的int32_t,反之亦然。当读取(语言不可知的)协议之后的序列化数据时,这可能很有用 - 您提取一个int并将其转换为struct eg以匹配协议中定义的字段和字段大小。您也可以跳过转换,只是将int大小的块读入这样的结构中,指的是位域大小与协议字段大小相匹配。这在网络编程中非常普遍 - 如果你想在协议之后发送数据包,你只需填充你的结构,序列化和传输。

请注意pragma pack不是标准的C,但它被各种常见的编译器认可。但是,如果没有编译指示包,编译器可以自由地在字段之间放置填充,从而降低上述用途的使用价值。

2

我想了解这种情况的真实用例吗?

例如,一些CPU的状态寄存器的结构可能看起来像这样:

enter image description here

为了通过结构来表示它,你可以使用位域

struct CSR 
{ 
    unsigned N: 1; 
    unsigned Z: 1; 
    unsigned C: 1; 
    unsigned V: 1; 
    unsigned : 20; 
    unsigned I: 1; 
    unsigned : 2; 
    unsigned M: 5; 
}; 

你可以在这里看到字段不是8的倍数,所以你不能使用int8_t或类似的东西。

1

你是对的,unsigned _int8的最后结构定义几乎等于使用​​:8的定义。几乎,因为字节顺序可以在这里有所作为,所以您可能会发现在两种情况下内存布局是相反的。

:8符号的主要目的是允许使用小数字节,如

struct foo { 
    uint32_t a:1; 
    uint32_t b:2; 
    uint32_t c:3; 
    uint32_t d:4; 
    uint32_t e:5; 
    uint32_t f:6; 
    uint32_t g:7; 
    uint32_t h:4; 
} 

为了减少填充,我强烈建议学习填充规则自己,他们并不难理解。如果你这样做,你可以知道你的版本unsigned _int8没有添加任何填充。或者,如果您不想学习这些规则,只需在您的结构上使用__attribute__((__packed__)),但这可能会导致严重的性能损失。