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 <mse...@gmail.com> 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
>

Reply via email to