Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ gcc和MSFT CL之间的位字段结构大小不同_C++_C++11_Gcc_Visual C++_Bit Fields - Fatal编程技术网

C++ gcc和MSFT CL之间的位字段结构大小不同

C++ gcc和MSFT CL之间的位字段结构大小不同,c++,c++11,gcc,visual-c++,bit-fields,C++,C++11,Gcc,Visual C++,Bit Fields,我有以下代码: #include <cstdint> #pragma pack(1) using MyType_t = union { uint8_t buffer[16]; struct { uint64_t a : 55; uint64_t b : 24; uint64_t c : 1; uint64_t d

我有以下代码:

#include <cstdint>

#pragma pack(1)
using MyType_t = union {
    uint8_t buffer[16];
    struct {
        uint64_t  a         : 55;   
        uint64_t  b         : 24;   
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
};
#pragma pack()

int main()
{
    return sizeof(MyType_t);
}
x86-64 gcc 6.3(-O3)

main:                                   # @main
        mov     eax, 16
        ret
x86-64 CL 19 2017 RTW(-Ox)

main:                                   # @main
        mov     eax, 16
        ret

是VisualC++编译器bug还是未定义行为?< /P> < P>我相信这是未定义的行为。NathanOliver给出了正确的答案:GCC和Clang跨越了两个

uint64\t
值。但是,阅读时会有一个代价:在where上看到这个非常相似的代码示例,GCC现在必须读取两个字段并进行一些数学运算以给出第二个值。

如果您希望两个编译器之间的两个布局保持一致,可以使用GCC的
\uu属性(ms\u struct))
指令,使其使用Microsoft的位域布局算法:

using MyType_t 
= union {
    uint8_t buffer[16];
    struct  __attribute__((ms_struct)) {
        uint64_t  a         : 55;   
        uint64_t  b         : 24;   
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
};
您也可以在GCC中使用
-mms位字段
选项,但这是一个ABI更改选项,可能会破坏其他代码

如果你想换一种方式,强迫微软的编译器使用GCC的位域布局,我认为没有任何属性或选项可以做到这一点。您必须更改代码并拆分
b
成员,使其不跨越64位边界。比如:

#pragma pack(1)
typedef union {
    uint8_t buffer[16];
#ifdef USE_GCC_BITFIELDS
    struct __attribute__((gcc_struct))  {
        uint64_t  a         : 55;   
        uint64_t  b         : 24;   
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
    uint64_t get_a() { return fields.a; }
    uint64_t get_b() { return fields.b; }
    uint64_t get_c() { return fields.c; }
    uint64_t get_d() { return fields.d; }
#elif defined(USE_MS_BITFIELDS)
    struct {
        uint64_t  a         : 55;   
        uint64_t  bl        : 9;
        uint64_t  bh        : 15;  
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
    uint64_t get_a() { return fields.a; }
    uint64_t get_b() { return fields.bl | (fields.bh << 9); }
    uint64_t get_c() { return fields.c; }
    uint64_t get_d() { return fields.d; }
#else /* portable code that should work anywhere */
    unsigned long long get_ull(int i) {
        typedef unsigned long long ull; unsigned char *p = buffer + i;
        return (ull) p[0] | ((ull) p[1] << 8) | ((ull) p[2] << 16) | ((ull) p[3] <<  24)
            | ((ull) p[4] << 32) | ((ull) p[5] << 40) | (((ull) p[6]) << 48)
            | ((ull) p[7] << 56); }
    unsigned long long get_a() { return get_ull(0) & ((1ULL << 55) - 1); }
    unsigned get_b() { return (buffer[6] >> 7) | (buffer[7] << 1) 
            | (buffer[8] << 9) | ((buffer[9] & 0x7F) << 17); }
    unsigned get_c() { return buffer[9] >> 7; }
    unsigned long long get_d() { return get_ull(8) >> 16; }
#endif

} MyType_t;
#pragma pack()
#pragma包(1)
typedef联合{
uint8_t缓冲器[16];
#ifdef使用\u GCC\u位字段
结构属性((gcc结构)){
uint64_t a:55;
uint64_t b:24;
uint64_t c:1;
uint64_t d:48;
}田地;
uint64\u t get_a(){返回字段.a;}
uint64_t get_b(){返回字段.b;}
uint64_t get_c(){return fields.c;}
uint64\u t get_d(){return fields.d;}
#定义的elif(使用\u MS\u位字段)
结构{
uint64_t a:55;
uint64\u t bl:9;
uint64_t bh:15;
uint64_t c:1;
uint64_t d:48;
}田地;
uint64\u t get_a(){返回字段.a;}

uint64_t get_b(){return fields.bl|(fields.bh几乎所有使用bitfeilds的内容都是实现定义的行为。您最可能看到的是gcc/clang非常聪明,将4个字段优化为2个
uint64_t
s,其中MSV添加了一个额外的字段,这样您就不会有跨越两个
uint64_t
s的位字段。hanks,我不想添加填充,我想使用I不依赖记忆。
#pragma pack(1)
typedef union {
    uint8_t buffer[16];
#ifdef USE_GCC_BITFIELDS
    struct __attribute__((gcc_struct))  {
        uint64_t  a         : 55;   
        uint64_t  b         : 24;   
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
    uint64_t get_a() { return fields.a; }
    uint64_t get_b() { return fields.b; }
    uint64_t get_c() { return fields.c; }
    uint64_t get_d() { return fields.d; }
#elif defined(USE_MS_BITFIELDS)
    struct {
        uint64_t  a         : 55;   
        uint64_t  bl        : 9;
        uint64_t  bh        : 15;  
        uint64_t  c         : 1;    
        uint64_t  d         : 48;   
    }fields;
    uint64_t get_a() { return fields.a; }
    uint64_t get_b() { return fields.bl | (fields.bh << 9); }
    uint64_t get_c() { return fields.c; }
    uint64_t get_d() { return fields.d; }
#else /* portable code that should work anywhere */
    unsigned long long get_ull(int i) {
        typedef unsigned long long ull; unsigned char *p = buffer + i;
        return (ull) p[0] | ((ull) p[1] << 8) | ((ull) p[2] << 16) | ((ull) p[3] <<  24)
            | ((ull) p[4] << 32) | ((ull) p[5] << 40) | (((ull) p[6]) << 48)
            | ((ull) p[7] << 56); }
    unsigned long long get_a() { return get_ull(0) & ((1ULL << 55) - 1); }
    unsigned get_b() { return (buffer[6] >> 7) | (buffer[7] << 1) 
            | (buffer[8] << 9) | ((buffer[9] & 0x7F) << 17); }
    unsigned get_c() { return buffer[9] >> 7; }
    unsigned long long get_d() { return get_ull(8) >> 16; }
#endif

} MyType_t;
#pragma pack()