问题
I can't find anywhere in the C standard where this is specified. For example, in
struct { signed int x:1; } foo;
is foo.x
an lvalue of type int
, or something else? It seems unnatural for it to be an lvalue of type int
since you cannot store any value of type int
in it, only 0 or -1, but I can't find any language that would assign it a different type. Of course, used in most expressions, it would get promoted to int
anyway, but the actual type makes a difference in C11 with _Generic
, and I can't find any language in the standard about how bitfields interact with _Generic
either.
回答1:
As Jonathan already cited, p5 clearly states what the type a bit-field has.
What you should have also in mind is that there is a special rule for bit-field arithmetic conversions in 6.3.1.1, basically stating that if an int
can represent all values such a bit-field converts to an int
in most expressions.
What the type would be in a _Generic
should be the declared type (modulo the sign glitch), since it seems to be consensus that arithmetic conversions don't apply, there. So
_Generic((X), int: toto, unsigned: tutu)
_Generic(+(X), int: toto, unsigned: tutu)
could give you different results if X
is an unsigned bit-field with a width that has all values fit into an int
.
回答2:
Given that you included the signed
qualifier, then the only values that can be stored in the 1-bit bit field are indeed -1 and 0. If you'd omitted the qualifier, it would be implementation defined whether the 'plain' int
bit field was signed or unsigned. If you'd specified unsigned int
, of course, the values would be 0 and +1.
The relevant sections of the standard are:
§6.7.2.1 Structure and union specifiers
¶4 The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted.122) If the value is zero, the declaration shall have no declarator.
¶5 A bit-field shall have a type that is a qualified or unqualified version of
_Bool
,signed int
,unsigned int
, or some other implementation-defined type. It is implementation-defined whether atomic types are permitted.¶10 A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits.125) If the value 0 or 1 is stored into a nonzero-width bit-field of type
_Bool
, the value of the bit-field shall compare equal to the value stored; a_Bool
bit-field has the semantics of a_Bool
.122) While the number of bits in a
_Bool
object is at leastCHAR_BIT
, the width (number of sign and value bits) of a_Bool
may be just 1 bit.125) As specified in 6.7.2 above, if the actual type specifier used is
int
or a typedef-name defined asint
, then it is implementation-defined whether the bit-field is signed or unsigned.
The footnote 125 points to:
§6.7.2 Type Specifiers
¶5 Each of the comma-separated multisets designates the same type, except that for bitfields, it is implementation-defined whether the specifier
int
designates the same type assigned int
or the same type asunsigned int
.
回答3:
The C11 specification certainly does not make this clear, and is perhaps deficient.
I believe that foo.x
is an lvalue with type other than int
, but my justification is pretty weak:
6.2.7 paragraph 1 says:
Two types have compatible type if their types are the same.
6.3 paragraph 2 says:
Conversion of an operand value to a compatible type causes no change to the value or the representation.
If foo.x
is an lvalue of type int
, then it would be compatible with other int
s so foo.x = 5
should result in foo.x
having value 5
(per 6.3p2). That obviously can't happen, suggesting that foo.x
is not compatible with int
, suggesting that foo.x
is not an lvalue of type int
.
It doesn't really make sense that foo.x
isn't compatible with int
. Maybe no conversion (in the 6.3.1 sense) occurs, and that foo.x
obtains its value via some mechanism not discussed in the standard. Or maybe I'm misunderstanding what "arithmetic operands" means, and that 6.3.1 doesn't apply to lvalues.
There's also 6.3.1.1 paragraph 1 bullet 2, which says:
- The rank of a signed integer type shall be greater than the rank of any signed integer type with less precision.
foo.x
has less precision than an ordinary int
(when used as an lvalue, not when it "is converted to the value stored in the designated object" as described in 6.3.2.1p2), so it must have a different integer conversion rank. This also suggests that it is not an int
.
But I'm not sure that my interpretation is valid or matches the intention of the committee.
I would recommend submitting a defect report about this.
回答4:
The C11 Standard states in 6.7.2.1p5:
A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.
This is a constraint, meaning, if a program declares a bit field with a type that does not fall into one of the categories above, a diagnostic must be printed.
However it then goes on to say in 6.7.2.1p10:
A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits.
I believe what they mean is that, while you must declare the bit field with something like signed int x:n
, the type of the lvalue expression foo.x
is some other signed integer type, call it T. T is a signed integer type consisting of n bits and must comply with the constraints on all signed integer types given in Sec. 6.2.6. But T is not necessarily compatible with the standard signed integer type named signed int
. (In fact, the only situation in which it is possible for T to be compatible with that standard type is if n happens to equal the number of bits in a signed int.)
Unfortunately, the Standard does not provide any means to name the type T, so I can't see how it can be used in a _Generic
, at least, not in a portable way. Specific implementations of the C language may provide a mechanism to name this type, but the Standard does not force them to.
回答5:
... the actual type makes a difference in C11 with
_Generic
The results of how 1 compiler treats the bit field types is shown below.
The 8-bit and 32-bit fields match the usual suspects.
What is the type of a 1-bit bitfield? As others have cited, its "name" is not clearly specified, but it is not any of the expected standard types.
This does not cite a specification, but does demonstrate how a respected compiler interpreted the C spec.
GNU C11 (GCC) version 5.3.0 (i686-pc-cygwin)
compiled by GNU C version 5.3.0, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3
#define info_typename(X) _Generic((X), \
_Bool: "_Bool", \
unsigned char: "unsigned char", \
signed char: "signed char", \
char: "char", \
int: "int", \
unsigned : "unsigned", \
default: "default" \
)
#define TYPE_NAME(t) { printf("%s\n", info_typename(t)); }
#include <stdio.h>
int main() {
struct {
signed int x1 :1;
signed int x8 :8;
signed int x32 :32;
_Bool b;
signed char sc;
char c;
unsigned char uc;
int i;
unsigned u;
} foo;
TYPE_NAME(foo.b);
TYPE_NAME(foo.sc);
TYPE_NAME(foo.c);
TYPE_NAME(foo.uc);
TYPE_NAME(foo.i);
TYPE_NAME(foo.u);
TYPE_NAME(foo.x1);
TYPE_NAME(foo.x8);
TYPE_NAME(foo.x32);
}
Output
_Bool
signed char
char
unsigned char
int
unsigned
default (int:1)
signed char (int:8)
int (int:32)
Note with -Wconversion
and the below code, I get this warning. So that is at least what one compiler calls its small bit field type: unsigned char:3
.
warning: conversion to 'unsigned char:3' from 'unsigned int' may alter its value [-Wconversion]
struct {
unsigned int x3 :3;
} foo;
unsigned u = 1;
foo.x3 = u; // warning
回答6:
I would suspect that this would depend on:
- The compiler
- Optimization settings
- The maximum number of bits in the bit field
回答7:
The type of a bit-field is:
bit-field of type T
where T
is either _Bool
, int
, signed int
, unsigned int
or some implementation-defined type.
In your example, foo.x
is of type: bit-field of type signed int
.
This is different than signed int
because the two types don't share the same constraints and requirements.
For example:
/* foo.x is of type bit-field of type signed int */
struct { signed int x:1; } foo;
/* y is of type signed int */
signed int y;
/* valid, taking the size of an expression of type signed int */
sizeof y;
/* not valid, taking the size of an expression of type bit-field
* of signed int */
sizeof foo.x;
/* valid, taking the address of a lvalue of type signed int */
&y;
/* invalid, taking the address of a lvalue of type bit-field
* of signed int */
&foo.x;
来源:https://stackoverflow.com/questions/13105313/what-is-the-type-of-a-bitfield