A bug in GCC implementation of bit-fields

隐身守侯 提交于 2019-12-04 03:02:45

The described behavior is incompatible with the C99 and C11 standards, but is provided for binary compatibility with the MSVC compiler (which has unusual struct packing behavior.)

Fortunately, it can be disabled either in the code with __attribute__((gcc_struct)) applied to the struct, or with the command-line switch -mno-ms-bitfields (see the documentation).

Using both GCC 4.7.1 (home-built) and GCC 4.2.1 (LLVM/clang†) on Mac OS X 10.7.4 with a 64-bit compilation, this code yields 4 in -std=c99 mode:

#include <stdio.h>

int main(void)
{
    struct S
    {
        unsigned a : 4;
        _Bool    b : 1;
    };
    printf("%zu\n", sizeof(struct S));
    return 0;
}

That's half the size you're reporting on Windows. It seems surprisingly large to me (I would expect it to be size of 1 byte), but the rules of the platform are what they are. Basically, the compiler is not obliged to follow the rules you'd like; it may follow the rules of the platform it is run on, and where it has the chance, it may even define the rules of the platform it is run on.

This following program has mildly dubious behaviour (because it accesses u.i after u.s was last written to), but shows that the field a is stored in the 4 least significant bits and the field b is stored in the next bit:

#include <stdio.h>

int main(void)
{
    union
    {
        struct S
        {
            unsigned a : 4;
            _Bool    b : 1;
        } s;
        int i;
    } u;
    u.i = 0;
    u.s.a = 5;
    u.s.b = 1;
    printf("%zu\n", sizeof(struct S));
    printf("%zu\n", sizeof(u));
    printf("0x%08X\n", u.i);
    u.s.a = 0xC;
    u.s.b = 1;
    printf("0x%08X\n", u.i);
    return 0;
}

Output:

4
4
0x00000015
0x0000001C

† i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!