В соответствии со стандартом C11 (упомянутым в в этом ответе ), стандарт обязывает поддерживать следующие типы: _Bool
, signed int
и unsigned int
.Другие типы могут поддерживаться, но это зависит от реализации.
Я попытался использовать следующий код, чтобы увидеть, каковы типы битовых полей на практике:
#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) и ICC (https://godbolt.org/z/yC_U8C) вели себя как и ожидалось:
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
Но GCC (https://godbolt.org/z/FS89_b) ввел несколько проблем:
- Aоднобитовое битовое поле, определенное, кроме
_Bool
, не подходит ни для одного из типов, представленных в _Generic
:
ошибка: селектор типа _Generic типа unsigned char:1 'не совместим ни с одной ассоциацией
После комментирования строк, которые выдавали ошибки, я получил это:
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
Для меня unsigned short
, short
, unsigned char
и signed char
совершенно неожиданны здесь.
Я неправильно понял стандарт?Это ошибка GCC?
Похоже, что использование _Generic
даже для четко определенных вещей не переносимо ...