1

Why this piece of code is needed ?

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

} CorrId;

I did some investigation around it and found that this way we are limiting the memory consumption to just what we need. For E.g.

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;
}

Output:-

16
4

I want to understand the real use case of such scenarios? why can't we declare the struct something like this,

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

} CorrId_NEW;

Does this has something to do with compiler optimizations? Or, what are the benefits of declaring the structure that way?

Grzegorz Adam Kowalski
  • 5,243
  • 3
  • 29
  • 40
Bhupesh Pant
  • 4,053
  • 5
  • 45
  • 70

4 Answers4

2

I want to understand the real use case of such scenarios?

For example, structure of status register of some CPU may look like this:

enter image description here

In order to represent it via structure, you could use 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;
};

You can see here that fields are not multiplies of 8, so you can't use int8_t, or something similar.

Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
1

It's often used with pragma pack to create bitfields with labels, e.g.:

#pragma pack(0)

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

Can be cast for whatever purpose to an int32_t, and vice versa. This might be useful when reading serialized data that follows a (language agnostic) protocol -- you extract an int and cast it to a struct eg to match the fields and field sizes defined in the protocol. You could also skip the conversion and just read an int sized chunk into such a struct, point being that the bitfield sizes match the protocol field sizes. This is extremely common in network programming -- if you want to send a packet following the protocol, you just populate your struct, serialize, and transmit.

Note that pragma pack is not standard C but it is recognized by various common compilers. Without pragma pack, however, the compiler is free to place padding between fields, reducing the use value for the purposes described above.

CodeClown42
  • 11,194
  • 1
  • 32
  • 67
1

You are right, the last structure definition with unsigned _int8 is almost equivalent to the definition using :8. Almost, because byte order can make a difference here, so you might find that the memory layout is reversed in the two cases.

The main purpose of the :8 notation is to allow the use of fractional bytes, as in

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;
}

To minimize padding, I strongly suggest to learn the padding rules yourself, they are not hard to grasp. If you do, you can know that your version with unsigned _int8 does not add any padding. Or, if you don't feel like learning those rules, just use __attribute__((__packed__)) on your struct, but that may introduce a severe performance penalty.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
1

Lets see a simple scenario,

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

};

Above case all work is done in 32-bits only.

But if you use just a integer it would have taken 4*32 bits.

If we take age as 32-bit integer, It can store in range of 0 to 2^32. But don't forget a normal person's age is just max 100 or 140 or 150 (even somebody studying in this age also), which needs max 8-bits to store, So why to waste remaining 24-bits.

surender8388
  • 474
  • 3
  • 12