I've tried you hack, but it doesn't work with "long bit fields". Also,
I've run into another problem. Instead of using unsigned char for
the bit field I changed it to a long unsigned int:33 and now I can't
print it without a warning.
Here is my Makefile:
CC = gcc
O = 3
X = c
STD = c11
CFLAGS = -m64 -Wall -std=$(STD)
all: test
test.o: test.c
$(CC) -x $(X) -O$(O) $(CFLAGS) -o test.o -c test.c
objdump -d test.o > test.txt
test: test.o
$(CC) $(CFLAGS) test.o -o test
clean:
rm -f test test.o test.txt
Here is the test:
#include <stdio.h>
struct big_bit_fields {
long unsigned int b33:33;
} __attribute__((__packed__));
_Static_assert(sizeof(struct big_bit_fields) == 5,
L"big_bit_fields is not 5 bytes");
#define type_to_str(__x) _Generic((0)?(__x):(__x), \
_Bool : "_Bool", \
char : "char", \
signed char : "unsigned char", \
unsigned char : "unsigned char", \
short int : "short int", \
unsigned short int: "unsigned short int", \
int : "int", \
unsigned int : "unsigned int", \
long int : "long int", \
long unsigned int : "long unsigned int", \
long long int : "long long int", \
long long unsigned int : "long long unsigned int", \
default : "unknown type")
int main(void) {
struct big_bit_fields bbf = { .b33 = 0x1FFFFFFFF };
printf("bbf.b33=0x%lx\n", bbf.b33);
printf(" type=%s\n", type_to_str(bbf.b33));
printf(" <<1 =0x%016lx\n", bbf.b33 << 1);
printf(" (ull)<<1 =0x%016lx\n", (long unsigned int)bbf.b33 << 1);
return 0;
}
Here the compile and run:
$ make clean ; make ; ./test
rm -f test test.o test.txt
gcc -x c -O3 -m64 -Wall -std=c11 -o test.o -c test.c
test.c: In function ‘main’:
test.c:44:10: warning: format ‘%lx’ expects argument of type ‘long
unsigned int’, but argument 2 has type ‘long unsigned int:33’
[-Wformat=]
printf("bbf.b33=0x%lx\n", bbf.b33);
^
test.c:46:10: warning: format ‘%lx’ expects argument of type ‘long
unsigned int’, but argument 2 has type ‘long unsigned int:33’
[-Wformat=]
printf(" <<1 =0x%016lx\n", bbf.b33 << 1);
^
objdump -d test.o > test.txt
gcc -m64 -Wall -std=c11 test.o -o test
bbf.b33=0x1ffffffff
type=unknown type
<<1 =0x00000001fffffffe
(ull)<<1 =0x00000003fffffffe
On Fri, Feb 19, 2016 at 1:35 PM, Martin Sebor <[email protected]> wrote:
> On 02/19/2016 11:25 AM, Wink Saville wrote:
>>
>> I'm using gcc 5.3.0:
>>
>> $ gcc --version
>> gcc (GCC) 5.3.0
>> Copyright (C) 2015 Free Software Foundation, Inc.
>> This is free software; see the source for copying conditions. There is NO
>> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
>> PURPOSE.
>>
>>
>> And I've tried to use _Generic to print the type of a bit field but
>> the compiler fails with:
>>
>> $ make
>> gcc -Wall -std=c11 -o test.o -c test.c
>> test.c: In function ‘main’:
>> test.c:8:35: error: ‘_Generic’ selector of type ‘unsigned char:2’ is
>> not compatible with any association
>> #define type_to_str(__x) _Generic((__x), \
>> ^
>> test.c:17:18: note: in expansion of macro ‘type_to_str’
>> printf("%s\n", type_to_str(b.f1));
>> ^
>> Makefile:7: recipe for target 'test.o' failed
>> make: *** [test.o] Error 1
>> bash: ./test: No such file or directory
>>
>>
>> The test program is:
>>
>> $ cat test.c
>> #include <stdio.h>
>>
>> struct bits {
>> unsigned char f0;
>> unsigned char f1:2;
>> };
>>
>> #define type_to_str(__x) _Generic((__x), \
>> unsigned char : "unsigned char")
>>
>> int main(void) {
>> struct bits b = { .f0 = 255, .f1 = 3 };
>>
>> printf("%d\n", b.f0);
>> printf("%s\n", type_to_str(b.f0));
>> printf("%d\n", b.f1);
>> printf("%s\n", type_to_str(b.f1));
>>
>> return 0;
>> }
>>
> ...
>>
>> How do I create a type association for a bit field?
>
>
> I suspect this falls under the set of issues that fall under bug
> 65471 - type interpretation in _Generic. The C language rules
> for _Generic aren't completely clear about what conversions are
> to take place. It would be helpful if you could your test case
> to the bug to make sure the bitfield case is considered when
> the issue is discussed by the C committee.
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65471
>
> The only idea for a workaround that comes to mind is to trick GCC
> into forgetting that it's a bit-field. This hack seems to work:
>
> #define type_to_str(__x) _Generic((0)?(__x):(__x), \
>
> Martin
>