Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
468 views
in Technique[技术] by (71.8m points)

c - Why aren't bitfields allowed with normal variables?

I wonder why bitfields work with unions/structs but not with a normal variable like int or short.
This works:

struct foo {
    int bar : 10;
};

But this fails:

int bar : 10; // "Expected ';' at end of declaration"

Why is this feature only available in unions/structs and not with variables? Isn't it technical the same?


Edit:

If it would be allowed you could make a variable with 3 bytes for instance without using the struct/union member each time. This is how I would to it with a struct:

struct int24_t {
    int x : 24 __attribute__((packed));
};

struct int24_t var; // sizeof(var) is now 3
// access the value would be easier:
var.x = 123;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a subjective question, "Why does the spec say this?" But I'll give it my shot.

Variables in a function normally have "automatic" storage, as opposed to one of the other durations (static duration, thread duration, and allocated duration).

In a struct, you are explicitly defining the memory layout of some object. But in a function, the compiler automatically allocates storage in some unspecified manner to your variables. Here's a question: how many bytes does x take up on the stack?

// sizeof(unsigned) == 4
unsigned x;

It could take up 4 bytes, or it could take up 8, or 12, or 0, or it could get placed in three different registers at the same time, or the stack and a register, or it could get four places on the stack.

The point is that the compiler is doing the allocation for you. Since you are not doing the layout of the stack, you should not specify the bit widths.

Extended discussion: Bitfields are actually a bit special. The spec states that adjacent bitfields get packed into the same storage unit. Bitfields are not actually objects.

  1. You cannot sizeof() a bit field.

  2. You cannot malloc() a bit field.

  3. You cannot &addressof a bit field.

All of these things you can do with objects in C, but not with bitfields. Bitfields are a special thing made just for structures and nowhere else.

About int24_t (updated): It works on some architectures, but not others. It is not even slightly portable.

typedef struct {
    int x : 24 __attribute__((packed));
} int24_t;

On Linux ELF/x64, OS X/x86, OS X/x64, sizeof(int24_t) == 3. But on OS X/PowerPC, sizeof(int24_t) == 4.

Note the code GCC generates for loading int24_t is basically equivalent to this:

int result = (((char *) ptr)[0] << 16) |
             (((unsigned char *) ptr)[1] << 8) |
             ((unsigned char *)ptr)[2];

It's 9 instructions on x64, just to load a single value.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...