Andrew Henle zasugerował ścisłą interpretację standardu C: typ pola bitowego jest liczbą całkowitą ze znakiem lub bez znaku o dokładnie określonej szerokości.
Oto test, który obsługuje tę interpretację: używając _Generic()
konstrukcji C1x próbuję określić typ pól bitowych o różnych szerokościach. Musiałem zdefiniować je za pomocą typu, long long int
aby uniknąć ostrzeżeń podczas kompilacji z clang.
Oto źródło:
#include <stdint.h>
#include <stdio.h>
#define typeof(X) _Generic((X), \
long double: "long double", \
double: "double", \
float: "float", \
unsigned long long int: "unsigned long long int", \
long long int: "long long int", \
unsigned long int: "unsigned long int", \
long int: "long int", \
unsigned int: "unsigned int", \
int: "int", \
unsigned short: "unsigned short", \
short: "short", \
unsigned char: "unsigned char", \
signed char: "signed char", \
char: "char", \
_Bool: "_Bool", \
__int128_t: "__int128_t", \
__uint128_t: "__uint128_t", \
default: "other")
#define stype long long int
#define utype unsigned long long int
struct s {
stype s1 : 1;
stype s2 : 2;
stype s3 : 3;
stype s4 : 4;
stype s5 : 5;
stype s6 : 6;
stype s7 : 7;
stype s8 : 8;
stype s9 : 9;
stype s10 : 10;
stype s11 : 11;
stype s12 : 12;
stype s13 : 13;
stype s14 : 14;
stype s15 : 15;
stype s16 : 16;
stype s17 : 17;
stype s18 : 18;
stype s19 : 19;
stype s20 : 20;
stype s21 : 21;
stype s22 : 22;
stype s23 : 23;
stype s24 : 24;
stype s25 : 25;
stype s26 : 26;
stype s27 : 27;
stype s28 : 28;
stype s29 : 29;
stype s30 : 30;
stype s31 : 31;
stype s32 : 32;
stype s33 : 33;
stype s34 : 34;
stype s35 : 35;
stype s36 : 36;
stype s37 : 37;
stype s38 : 38;
stype s39 : 39;
stype s40 : 40;
stype s41 : 41;
stype s42 : 42;
stype s43 : 43;
stype s44 : 44;
stype s45 : 45;
stype s46 : 46;
stype s47 : 47;
stype s48 : 48;
stype s49 : 49;
stype s50 : 50;
stype s51 : 51;
stype s52 : 52;
stype s53 : 53;
stype s54 : 54;
stype s55 : 55;
stype s56 : 56;
stype s57 : 57;
stype s58 : 58;
stype s59 : 59;
stype s60 : 60;
stype s61 : 61;
stype s62 : 62;
stype s63 : 63;
stype s64 : 64;
utype u1 : 1;
utype u2 : 2;
utype u3 : 3;
utype u4 : 4;
utype u5 : 5;
utype u6 : 6;
utype u7 : 7;
utype u8 : 8;
utype u9 : 9;
utype u10 : 10;
utype u11 : 11;
utype u12 : 12;
utype u13 : 13;
utype u14 : 14;
utype u15 : 15;
utype u16 : 16;
utype u17 : 17;
utype u18 : 18;
utype u19 : 19;
utype u20 : 20;
utype u21 : 21;
utype u22 : 22;
utype u23 : 23;
utype u24 : 24;
utype u25 : 25;
utype u26 : 26;
utype u27 : 27;
utype u28 : 28;
utype u29 : 29;
utype u30 : 30;
utype u31 : 31;
utype u32 : 32;
utype u33 : 33;
utype u34 : 34;
utype u35 : 35;
utype u36 : 36;
utype u37 : 37;
utype u38 : 38;
utype u39 : 39;
utype u40 : 40;
utype u41 : 41;
utype u42 : 42;
utype u43 : 43;
utype u44 : 44;
utype u45 : 45;
utype u46 : 46;
utype u47 : 47;
utype u48 : 48;
utype u49 : 49;
utype u50 : 50;
utype u51 : 51;
utype u52 : 52;
utype u53 : 53;
utype u54 : 54;
utype u55 : 55;
utype u56 : 56;
utype u57 : 57;
utype u58 : 58;
utype u59 : 59;
utype u60 : 60;
utype u61 : 61;
utype u62 : 62;
utype u63 : 63;
utype u64 : 64;
} x;
int main(void) {
#define X(v) printf("typeof(" #v "): %s\n", typeof(v))
X(x.s1);
X(x.s2);
X(x.s3);
X(x.s4);
X(x.s5);
X(x.s6);
X(x.s7);
X(x.s8);
X(x.s9);
X(x.s10);
X(x.s11);
X(x.s12);
X(x.s13);
X(x.s14);
X(x.s15);
X(x.s16);
X(x.s17);
X(x.s18);
X(x.s19);
X(x.s20);
X(x.s21);
X(x.s22);
X(x.s23);
X(x.s24);
X(x.s25);
X(x.s26);
X(x.s27);
X(x.s28);
X(x.s29);
X(x.s30);
X(x.s31);
X(x.s32);
X(x.s33);
X(x.s34);
X(x.s35);
X(x.s36);
X(x.s37);
X(x.s38);
X(x.s39);
X(x.s40);
X(x.s41);
X(x.s42);
X(x.s43);
X(x.s44);
X(x.s45);
X(x.s46);
X(x.s47);
X(x.s48);
X(x.s49);
X(x.s50);
X(x.s51);
X(x.s52);
X(x.s53);
X(x.s54);
X(x.s55);
X(x.s56);
X(x.s57);
X(x.s58);
X(x.s59);
X(x.s60);
X(x.s61);
X(x.s62);
X(x.s63);
X(x.s64);
X(x.u1);
X(x.u2);
X(x.u3);
X(x.u4);
X(x.u5);
X(x.u6);
X(x.u7);
X(x.u8);
X(x.u9);
X(x.u10);
X(x.u11);
X(x.u12);
X(x.u13);
X(x.u14);
X(x.u15);
X(x.u16);
X(x.u17);
X(x.u18);
X(x.u19);
X(x.u20);
X(x.u21);
X(x.u22);
X(x.u23);
X(x.u24);
X(x.u25);
X(x.u26);
X(x.u27);
X(x.u28);
X(x.u29);
X(x.u30);
X(x.u31);
X(x.u32);
X(x.u33);
X(x.u34);
X(x.u35);
X(x.u36);
X(x.u37);
X(x.u38);
X(x.u39);
X(x.u40);
X(x.u41);
X(x.u42);
X(x.u43);
X(x.u44);
X(x.u45);
X(x.u46);
X(x.u47);
X(x.u48);
X(x.u49);
X(x.u50);
X(x.u51);
X(x.u52);
X(x.u53);
X(x.u54);
X(x.u55);
X(x.u56);
X(x.u57);
X(x.u58);
X(x.u59);
X(x.u60);
X(x.u61);
X(x.u62);
X(x.u63);
X(x.u64);
return 0;
}
Oto wynik działania programu skompilowany z 64-bitowym clangiem:
typeof(x.s1): long long int
typeof(x.s2): long long int
typeof(x.s3): long long int
typeof(x.s4): long long int
typeof(x.s5): long long int
typeof(x.s6): long long int
typeof(x.s7): long long int
typeof(x.s8): long long int
typeof(x.s9): long long int
typeof(x.s10): long long int
typeof(x.s11): long long int
typeof(x.s12): long long int
typeof(x.s13): long long int
typeof(x.s14): long long int
typeof(x.s15): long long int
typeof(x.s16): long long int
typeof(x.s17): long long int
typeof(x.s18): long long int
typeof(x.s19): long long int
typeof(x.s20): long long int
typeof(x.s21): long long int
typeof(x.s22): long long int
typeof(x.s23): long long int
typeof(x.s24): long long int
typeof(x.s25): long long int
typeof(x.s26): long long int
typeof(x.s27): long long int
typeof(x.s28): long long int
typeof(x.s29): long long int
typeof(x.s30): long long int
typeof(x.s31): long long int
typeof(x.s32): long long int
typeof(x.s33): long long int
typeof(x.s34): long long int
typeof(x.s35): long long int
typeof(x.s36): long long int
typeof(x.s37): long long int
typeof(x.s38): long long int
typeof(x.s39): long long int
typeof(x.s40): long long int
typeof(x.s41): long long int
typeof(x.s42): long long int
typeof(x.s43): long long int
typeof(x.s44): long long int
typeof(x.s45): long long int
typeof(x.s46): long long int
typeof(x.s47): long long int
typeof(x.s48): long long int
typeof(x.s49): long long int
typeof(x.s50): long long int
typeof(x.s51): long long int
typeof(x.s52): long long int
typeof(x.s53): long long int
typeof(x.s54): long long int
typeof(x.s55): long long int
typeof(x.s56): long long int
typeof(x.s57): long long int
typeof(x.s58): long long int
typeof(x.s59): long long int
typeof(x.s60): long long int
typeof(x.s61): long long int
typeof(x.s62): long long int
typeof(x.s63): long long int
typeof(x.s64): long long int
typeof(x.u1): unsigned long long int
typeof(x.u2): unsigned long long int
typeof(x.u3): unsigned long long int
typeof(x.u4): unsigned long long int
typeof(x.u5): unsigned long long int
typeof(x.u6): unsigned long long int
typeof(x.u7): unsigned long long int
typeof(x.u8): unsigned long long int
typeof(x.u9): unsigned long long int
typeof(x.u10): unsigned long long int
typeof(x.u11): unsigned long long int
typeof(x.u12): unsigned long long int
typeof(x.u13): unsigned long long int
typeof(x.u14): unsigned long long int
typeof(x.u15): unsigned long long int
typeof(x.u16): unsigned long long int
typeof(x.u17): unsigned long long int
typeof(x.u18): unsigned long long int
typeof(x.u19): unsigned long long int
typeof(x.u20): unsigned long long int
typeof(x.u21): unsigned long long int
typeof(x.u22): unsigned long long int
typeof(x.u23): unsigned long long int
typeof(x.u24): unsigned long long int
typeof(x.u25): unsigned long long int
typeof(x.u26): unsigned long long int
typeof(x.u27): unsigned long long int
typeof(x.u28): unsigned long long int
typeof(x.u29): unsigned long long int
typeof(x.u30): unsigned long long int
typeof(x.u31): unsigned long long int
typeof(x.u32): unsigned long long int
typeof(x.u33): unsigned long long int
typeof(x.u34): unsigned long long int
typeof(x.u35): unsigned long long int
typeof(x.u36): unsigned long long int
typeof(x.u37): unsigned long long int
typeof(x.u38): unsigned long long int
typeof(x.u39): unsigned long long int
typeof(x.u40): unsigned long long int
typeof(x.u41): unsigned long long int
typeof(x.u42): unsigned long long int
typeof(x.u43): unsigned long long int
typeof(x.u44): unsigned long long int
typeof(x.u45): unsigned long long int
typeof(x.u45): unsigned long long int
typeof(x.u46): unsigned long long int
typeof(x.u47): unsigned long long int
typeof(x.u48): unsigned long long int
typeof(x.u49): unsigned long long int
typeof(x.u50): unsigned long long int
typeof(x.u51): unsigned long long int
typeof(x.u52): unsigned long long int
typeof(x.u53): unsigned long long int
typeof(x.u54): unsigned long long int
typeof(x.u55): unsigned long long int
typeof(x.u56): unsigned long long int
typeof(x.u57): unsigned long long int
typeof(x.u58): unsigned long long int
typeof(x.u59): unsigned long long int
typeof(x.u60): unsigned long long int
typeof(x.u61): unsigned long long int
typeof(x.u62): unsigned long long int
typeof(x.u63): unsigned long long int
typeof(x.u64): unsigned long long int
Wszystkie pola bitowe wydają się mieć określony typ, a nie typ specyficzny dla określonej szerokości.
Oto wyjście programu skompilowane z 64-bitowym gcc:
typestr(x.s1): other
typestr(x.s2): other
typestr(x.s3): other
typestr(x.s4): other
typestr(x.s5): other
typestr(x.s6): other
typestr(x.s7): other
typestr(x.s8): signed char
typestr(x.s9): other
typestr(x.s10): other
typestr(x.s11): other
typestr(x.s12): other
typestr(x.s13): other
typestr(x.s14): other
typestr(x.s15): other
typestr(x.s16): short
typestr(x.s17): other
typestr(x.s18): other
typestr(x.s19): other
typestr(x.s20): other
typestr(x.s21): other
typestr(x.s22): other
typestr(x.s23): other
typestr(x.s24): other
typestr(x.s25): other
typestr(x.s26): other
typestr(x.s27): other
typestr(x.s28): other
typestr(x.s29): other
typestr(x.s30): other
typestr(x.s31): other
typestr(x.s32): int
typestr(x.s33): other
typestr(x.s34): other
typestr(x.s35): other
typestr(x.s36): other
typestr(x.s37): other
typestr(x.s38): other
typestr(x.s39): other
typestr(x.s40): other
typestr(x.s41): other
typestr(x.s42): other
typestr(x.s43): other
typestr(x.s44): other
typestr(x.s45): other
typestr(x.s46): other
typestr(x.s47): other
typestr(x.s48): other
typestr(x.s49): other
typestr(x.s50): other
typestr(x.s51): other
typestr(x.s52): other
typestr(x.s53): other
typestr(x.s54): other
typestr(x.s55): other
typestr(x.s56): other
typestr(x.s57): other
typestr(x.s58): other
typestr(x.s59): other
typestr(x.s60): other
typestr(x.s61): other
typestr(x.s62): other
typestr(x.s63): other
typestr(x.s64): long long int
typestr(x.u1): other
typestr(x.u2): other
typestr(x.u3): other
typestr(x.u4): other
typestr(x.u5): other
typestr(x.u6): other
typestr(x.u7): other
typestr(x.u8): unsigned char
typestr(x.u9): other
typestr(x.u10): other
typestr(x.u11): other
typestr(x.u12): other
typestr(x.u13): other
typestr(x.u14): other
typestr(x.u15): other
typestr(x.u16): unsigned short
typestr(x.u17): other
typestr(x.u18): other
typestr(x.u19): other
typestr(x.u20): other
typestr(x.u21): other
typestr(x.u22): other
typestr(x.u23): other
typestr(x.u24): other
typestr(x.u25): other
typestr(x.u26): other
typestr(x.u27): other
typestr(x.u28): other
typestr(x.u29): other
typestr(x.u30): other
typestr(x.u31): other
typestr(x.u32): unsigned int
typestr(x.u33): other
typestr(x.u34): other
typestr(x.u35): other
typestr(x.u36): other
typestr(x.u37): other
typestr(x.u38): other
typestr(x.u39): other
typestr(x.u40): other
typestr(x.u41): other
typestr(x.u42): other
typestr(x.u43): other
typestr(x.u44): other
typestr(x.u45): other
typestr(x.u46): other
typestr(x.u47): other
typestr(x.u48): other
typestr(x.u49): other
typestr(x.u50): other
typestr(x.u51): other
typestr(x.u52): other
typestr(x.u53): other
typestr(x.u54): other
typestr(x.u55): other
typestr(x.u56): other
typestr(x.u57): other
typestr(x.u58): other
typestr(x.u59): other
typestr(x.u60): other
typestr(x.u61): other
typestr(x.u62): other
typestr(x.u63): other
typestr(x.u64): unsigned long long int
Co jest zgodne z każdą szerokością o innym typie.
Wyrażenie E1 << E2
ma typ promowanego lewego operandu, więc dowolna szerokość mniejsza niż INT_WIDTH
jest promowana int
poprzez promocję liczb całkowitych i dowolna szerokość większa niż INT_WIDTH
pozostawiona sama. Wynik wyrażenia powinien być rzeczywiście obcięty do szerokości pola bitowego, jeśli ta szerokość jest większa niżINT_WIDTH
. Mówiąc dokładniej, powinien zostać obcięty dla typu niepodpisanego i może być implementacją zdefiniowaną dla typów podpisanych.
To samo powinno wystąpić w przypadku E1 + E2
innych operatorów arytmetycznych, jeśli E1
lub E2
są polami bitowymi o szerokości większej niż int
. Argument o mniejszej szerokości jest konwertowany na typ o większej szerokości, a wynik ma również typ typu. To bardzo sprzeczne z intuicją zachowanie, które powoduje wiele nieoczekiwanych wyników, może być przyczyną powszechnego przekonania, że pola bitowe są fałszywe i należy ich unikać.
Wydaje się, że wiele kompilatorów nie zgadza się z tą interpretacją standardu C, a interpretacja ta nie jest oczywista z obecnego brzmienia. Przydatne byłoby wyjaśnienie semantyki operacji arytmetycznych dotyczących operandów pola bitowego w przyszłej wersji standardu C.