This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

struct with members' sizes

I'm using C51 v3.20, and when I compiled the following structure, the compiler allocates 6 bytes for it.

typedef struct t_channel_info {
	int target_temp:9;
	unsigned char control_mode:2;
	unsigned char status:2;
	unsigned char warming:1;
	int current_temp:9;
	unsigned char warm_proportion;
} t_channel_info;

Should not it allocate only (9+2+2+1+9+8)/8=4 bytes?

But, when I partition a 9-bit integer to 8 and 1 bits chars, the size reduces to 5 bytes.

Is there an explanation?

Parents
  • The best you can do with a simple struct is 5 bytes:

    typedef struct t_channel_info
    {
        //int at 0-1
                 int target_temp:9;
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    
        //int at 2-3
    	         int current_temp:9;
    
        //char at 4
    	unsigned char warm_proportion:8;
    } t_channel_info;
    
    t_channel_info . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  5
      target_temp. . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  9.0
      control_mode . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.9
      status . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.11
      warming. . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  1.13
      current_temp . . . . . . . . . . . .  MEMBER   -----  FIELD    0002H  9.0
      warm_proportion. . . . . . . . . . .  MEMBER   -----  FIELD    0004H  8.0
    

    With a union you can get 4 bytes:
    (The structures are broken out to get a better cross reference.)

    struct PartA
    {
        //int at 0-1
                 int target_temp:9;
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    } a;
    
    struct PartB
    {
        //char at 0
                 char dummy1;
    
        //int at 1-2
    	         int dummy2:7;
    	         int current_temp:9;
    
        //char at 3
    	unsigned char warm_proportion;
    };
    
    typedef union
    {
    	struct PartA a;
    	struct PartB b;
    } t_channel_info2;
    
    t_channel_info2. . . . . . . . . . . .  TYPEDEF  -----  UNION    -----  4
      a. . . . . . . . . . . . . . . . . .  MEMBER   -----  STRUCT   0000H  2
      b. . . . . . . . . . . . . . . . . .  MEMBER   -----  STRUCT   0000H  4
    
    PartA. . . . . . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  2
      target_temp. . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  9.0
      control_mode . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.9
      status . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.11
      warming. . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  1.13
    
    PartB. . . . . . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  4
      dummy1 . . . . . . . . . . . . . . .  MEMBER   -----  CHAR     0000H  1
      dummy2 . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0001H  7.0
      current_temp . . . . . . . . . . . .  MEMBER   -----  FIELD    0001H  9.7
      warm_proportion. . . . . . . . . . .  MEMBER   -----  U_CHAR   0003H  1
    
    

Reply
  • The best you can do with a simple struct is 5 bytes:

    typedef struct t_channel_info
    {
        //int at 0-1
                 int target_temp:9;
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    
        //int at 2-3
    	         int current_temp:9;
    
        //char at 4
    	unsigned char warm_proportion:8;
    } t_channel_info;
    
    t_channel_info . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  5
      target_temp. . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  9.0
      control_mode . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.9
      status . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.11
      warming. . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  1.13
      current_temp . . . . . . . . . . . .  MEMBER   -----  FIELD    0002H  9.0
      warm_proportion. . . . . . . . . . .  MEMBER   -----  FIELD    0004H  8.0
    

    With a union you can get 4 bytes:
    (The structures are broken out to get a better cross reference.)

    struct PartA
    {
        //int at 0-1
                 int target_temp:9;
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    } a;
    
    struct PartB
    {
        //char at 0
                 char dummy1;
    
        //int at 1-2
    	         int dummy2:7;
    	         int current_temp:9;
    
        //char at 3
    	unsigned char warm_proportion;
    };
    
    typedef union
    {
    	struct PartA a;
    	struct PartB b;
    } t_channel_info2;
    
    t_channel_info2. . . . . . . . . . . .  TYPEDEF  -----  UNION    -----  4
      a. . . . . . . . . . . . . . . . . .  MEMBER   -----  STRUCT   0000H  2
      b. . . . . . . . . . . . . . . . . .  MEMBER   -----  STRUCT   0000H  4
    
    PartA. . . . . . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  2
      target_temp. . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  9.0
      control_mode . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.9
      status . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  2.11
      warming. . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0000H  1.13
    
    PartB. . . . . . . . . . . . . . . . .  * TAG *  -----  STRUCT   -----  4
      dummy1 . . . . . . . . . . . . . . .  MEMBER   -----  CHAR     0000H  1
      dummy2 . . . . . . . . . . . . . . .  MEMBER   -----  FIELD    0001H  7.0
      current_temp . . . . . . . . . . . .  MEMBER   -----  FIELD    0001H  9.7
      warm_proportion. . . . . . . . . . .  MEMBER   -----  U_CHAR   0003H  1
    
    

Children
  • Thanks for your kind replies.

    Based on your comments and links, I modified the struct as follows:

    typedef struct tt_channel_info {
    	unsigned int warm_proportion:7;
    	int target_temp:9;
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    	int current_temp:9;
    } tt_channel_info;
    
    tt_channel_info. . . . . . . . . . . .  TYPEDEF  -----  STRUCT   -----  4
      warm_proportion. . . . . . . . . . .  MEMBER   -----  FIELD    0000H  7.0
      target_temp. . . . . . . . . . . . .  MEMBER   DATA   FIELD    0000H  9.7
      control_mode . . . . . . . . . . . .  MEMBER   DATA   FIELD    0002H  2.0
      status . . . . . . . . . . . . . . .  MEMBER   DATA   FIELD    0002H  2.2
      warming. . . . . . . . . . . . . . .  MEMBER   DATA   FIELD    0002H  1.4
      current_temp . . . . . . . . . . . .  MEMBER   DATA   FIELD    0002H  9.5
    

    Yes, I changed the size of warm_proportion to 7 bits. It is OK to have values between 0-127 for this field.


  • Since you have control over the layout, I suggest the following modification to reduce code size and increase speed.

    typedef struct tt_channel_info {
    	int target_temp:9;  //keep the fields > 8 bits at int offset 0
    	unsigned int warm_proportion:7;
    
    	int current_temp:9; //keep the fields > 8 bits at int offset 0
    	unsigned int control_mode:2;
    	unsigned int status:2;
    	unsigned int warming:1;
    } tt_channel_info;