According to the C11 standard (mentioned in this answer), the standard forces the following types to be supported: _Bool
, signed int
and unsigned int
. Other types can be supported but it is up to the implementation.
I tried to following code to see what are the types of the bit-fields in practice:
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#define ARG_TYPE(arg) _Generic((arg), \
_Bool : "_Bool", \
char : "char", \
signed char : "signed char", \
unsigned char : "unsigned char", \
short : "short", \
unsigned short : "unsigned short", \
int : "int", \
unsigned int : "unsigned int", \
long : "long", \
unsigned long : "unsigned long", \
long long : "long long", \
unsigned long long : "unsigned long long")
int main(void)
{
struct _s
{
unsigned int uval32 : 32;
unsigned int uval16 : 16;
unsigned int uval8 : 8;
unsigned int uval1 : 1;
signed int ival32 : 32;
signed int ival16 : 16;
signed int ival8 : 8;
signed int ival1 : 1;
_Bool bool1 : 1;
} s = {0};
printf("The type of s.uval32 is %s\n", ARG_TYPE(s.uval32));
printf("The type of s.uval16 is %s\n", ARG_TYPE(s.uval16));
printf("The type of s.uval8 is %s\n", ARG_TYPE(s.uval8));
printf("The type of s.uval1 is %s\n", ARG_TYPE(s.uval1));
printf("The type of s.ival32 is %s\n", ARG_TYPE(s.ival32));
printf("The type of s.ival16 is %s\n", ARG_TYPE(s.ival16));
printf("The type of s.ival8 is %s\n", ARG_TYPE(s.ival8));
printf("The type of s.ival1 is %s\n", ARG_TYPE(s.ival1));
printf("The type of s.bool1 is %s\n", ARG_TYPE(s.bool1));
(void)s;
return 0;
}
Clang (https://godbolt.org/z/fjVRwI) and ICC (https://godbolt.org/z/yC_U8C) behaved as expected:
The type of s.uval32 is unsigned int
The type of s.uval16 is unsigned int
The type of s.uval8 is unsigned int
The type of s.uval1 is unsigned int
The type of s.ival32 is int
The type of s.ival16 is int
The type of s.ival8 is int
The type of s.ival1 is int
The type of s.bool1 is _Bool
But GCC (https://godbolt.org/z/FS89_b) introduced several issues:
- A single bit bit-field defined other than
_Bool
didn't fit any of the types introduced in the_Generic
:
error: '_Generic' selector of type 'unsigned char:1' is not compatible with any association
After commenting out the lines which issued errors I got this:
The type of s.uval32 is unsigned int The type of s.uval16 is unsigned short The type of s.uval8 is unsigned char The type of s.ival32 is int The type of s.ival16 is short The type of s.ival8 is signed char The type of s.bool1 is _Bool
To me,
unsigned short
,short
,unsigned char
andsigned char
are completely unexpected here.
Did I misunderstand the standard? Is this a GCC bug?
Looks like using _Generic
even for well defined stuff is not portable...