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;

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

4

4 回答 4

2

我想了解此类场景的真实用例?

例如,某些 CPU 的状态寄存器结构可能如下所示:

在此处输入图像描述

为了通过结构表示它,您可以使用bitfield

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或类似的东西。

于 2013-09-21T12:49:38.960 回答
1

没错,最后一个结构定义 withunsigned _int8几乎等同于 using 的定义: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__))在您的结构上使用,但这可能会导致严重的性能损失。

于 2013-09-21T13:01:03.950 回答
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 位。

于 2013-09-21T13:10:46.347 回答
1

它通常用于pragma pack创建带有标签的位域,例如:

#pragma pack(0)

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

可以出于任何目的转换为 a int32_t,反之亦然。这在读取遵循(与语言无关的)协议的序列化数据时可能很有用——您提取一个 int 并将其强制转换为 astruct eg以匹配协议中定义的字段和字段大小。您也可以跳过转换,只需将一个 int 大小的块读入这样的结构,即位域大小与协议字段大小匹配。这在网络编程中非常常见——如果你想按照协议发送一个数据包,你只需填充你的结构、序列化和传输。

请注意,这pragma pack不是标准 C,但它被各种常见的编译器识别。 但是,如果没有 pragma pack,编译器可以自由地在字段之间放置填充,从而减少用于上述目的的使用值。

于 2013-09-21T12:45:38.513 回答