简体   繁体   English

Visual Studio C ++位域结构大小问题

[英]Visual Studio C++ bitfield struct size problem

I have created and compiled following code in GCC using packed attribute and it worked like as expected. 我已经在GCC中使用packed属性创建和编译了以下代码,它按预期工作。 But in Visual Studio results are not same as GCC. 但是在Visual Studio中,结果与GCC不同。

#pragma pack(push, 1)
typedef struct
{
    uint8_t TargetID: 6;
    enum_OPCode OPCode: 3;
    uint8_t CRC7: 7;
} struct_commDataPack_request;
#pragma pack(pop)

As you can see size of all elements must be 16bits = 2Bytes which is true in GCC, but in Visual Studio it returns 3Bytes! 如您所见,所有元素的大小必须为16bits = 2Bytes,这在GCC中是正确的,但是在Visual Studio中,它将返回3Bytes! and if I decrease size of it to 15bits it will return 2Bytes. 如果我将其大小减小到15bits,它将返回2Bytes。

How can I fix it? 我该如何解决?

Well, packing is just too platform dependent to really rely on it. 好吧,打包太依赖平台而不能真正依赖它。

In VS, when you do "pack(push, 1)", you essentially set the padding to 8 bits and, as you saw, end up with three bytes (6 bits of which are padding). 在VS中,当您执行“ pack(push,1)”时,实际上将填充设置为8位,并且如您所见,最终以三个字节(其中6位为填充)结尾。

Padding on GCC however (in case you did it with __attribute__((packed)) or some alias for it) can be turned off completely. 但是,在GCC上的填充(如果您使用__attribute __((packed))或它的某些别名来填充)可以完全关闭。 That's why you see just 2 bytes. 这就是为什么您只看到2个字节的原因。

To keep it portable, why don't you just write your own small serialization routine? 为了保持可移植性,为什么不编写自己的小型序列化例程? Something like this: 像这样:

struct_commDataPack_request s;
short wire = s.TargetID | (s.OPCode<<6) | (s.CRC7 << 9);

I used this code to reproduce in VS2017: 我使用以下代码在VS2017中重现了:

#include <stdio.h>
#include <stdint.h>

typedef enum { A,B,C } enum_OPCode;

#pragma pack(push, 1)
typedef struct
{
  uint8_t TargetID : 6;
  uint8_t OPCode : 3;
  uint8_t CRC7 : 7;
} struct_commDataPack_request;
#pragma pack(pop)

int main()
{
  printf("%zd\n", sizeof(struct_commDataPack_request));
}

The size here is 3. 大小是3。

But when I change 但是当我改变

uint8_t OPCode : 3;
uint8_t CRC7 : 7;

to

uint8_t OPCode : 2;
uint8_t CRC7 : 8;

(overall size remains 16 bits), the size is 2. (总大小仍为16位),大小为2。

As suggested before, best is to write your own serialisation/deserialisation. 如前所述,最好是编写自己的序列化/反序列化。

As stated in MS document : MS文件中所述

The underlying type of a bit field must be an integral type. 位字段的基础类型必须是整数类型。 If a bit field would overflow the boundary of the declared type (in your case is uint8_t), new units of storage are allocated. 如果位字段溢出声明类型的边界(在您的情况下为uint8_t),则会分配新的存储单元。

A way to solve the problem is to use a declared type with a bigger boundary (uint16_t). 解决问题的一种方法是使用边界较大的声明类型(uint16_t)。

Here is the code I used: 这是我使用的代码:

#include "pch.h"
#include <stdio.h>
#include <stdint.h>

typedef enum { A, B, C } enum_OPCode;

#pragma pack(push, 1)
typedef struct
{
    uint16_t TargetID : 6;
    uint16_t OPCode : 3;
    uint16_t CRC7 : 7;
} struct_commDataPack_request;
#pragma pack(pop)

int main()
{
    struct_commDataPack_request packet;

    packet.TargetID = 0;
    packet.OPCode = 7;
    packet.CRC7 = 0;

    unsigned char * pData = (unsigned char *)&packet;

    printf("Packet size : %zd\n", sizeof(struct_commDataPack_request));
    for (int i = 0; i < sizeof(packet); i++) {
        printf("byte %d is [%02X]\n", i, pData[i] );
    }
}

The results : 结果 :

Packet size : 2
byte 0 is [C0]
byte 1 is [01]

( 0x01C0 in bits : 0000 0001 1100 0000) (0x01C0位:0000 0001 1100 0000)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM