I have isolated the problem to a very small test program. There are 2 tests in main, testa builds an anonymous union with bit-fields in it. testb builds a similar anonymous union but this time with a named structure in it but otherwise identical members. testa gives incorrect results (seems to ignore bit-fields). testb gives correct results. This is the output of the program. testa bf0.data=0 bf0.a=0 bf0.b=0 bf0.data=1 bf0.a=1 bf0.b=1 bf0.data=1 bf0.a=1 bf0.b=1 testb bf0.data=0 bf0.my.a=0 bf0.my.b=0 bf0.data=1 bf0.my.a=1 bf0.my.b=0 bf0.data=3 bf0.my.a=1 bf0.my.b=1 Environment: System: Linux lc-sj1-2293 2.6.9-67.ELsmp #1 SMP Wed Nov 7 13:56:44 EST 2007 x86_64 x86_64 x86_64 GNU/Linux Architecture: x86_64 host: x86_64-unknown-linux-gnu build: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu configured with: ./configure --prefix=/tools/oss/packages/x86_64-rhel4/gcc/4.1.1 --with-gnu-as --with-as=/tools/oss/packages/x86_64-rhel4/binutils/default/bin/as --with-gnu-ld --with-ld=/tools/oss/packages/x86_64-rhel4/binutils/default/bin/ld --enable-languages=c,c++,objc How-To-Repeat: #include <iostream> using namespace std; struct bfa { union { unsigned int a : 1, b : 4; unsigned int data; }; }; struct bfb { struct my_struct { unsigned int a : 1, b : 4; }; union { my_struct my; unsigned int data; }; }; void testa() { cout << __func__ << endl; bfa bf0; bf0.data = 0; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << bf0.b << endl; bf0.a = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << hex << bf0.b << endl; bf0.b = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << hex << bf0.b << endl; } void testb() { cout << __func__ << endl; bfb bf0; bf0.data = 0; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.my.a=" << bf0.my.a << endl; cout << "bf0.my.b=" << bf0.my.b << endl; bf0.my.a = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.my.a=" << bf0.my.a << endl; cout << "bf0.my.b=" << hex << bf0.my.b << endl; bf0.my.b = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.my.a=" << bf0.my.a << endl; cout << "bf0.my.b=" << hex << bf0.my.b << endl; } int main(int argc, char** argv) { testa(); testb(); return 0; }
Fix: As mentioned testb is a work-around for the coding style used in testa.
Without having seriously looked into your code, I note that two completely different, closed source compilers (ICC and SunStudio) leads to the same behavior as GCC at runtime. Does your code actually "work" (behaves like you expect) somewhere?
Subject: Re: Bug with anonymous unions and bit-fields That was fast and interesting that two other compilers behave the same. Unfortunately I don't have access to any other compiler. I am simply befuddled by the behavior though. I wouldn't file a bug, if I thought it was frivolous. paolo dot carlini at oracle dot com wrote: > ------- Comment #2 from paolo dot carlini at oracle dot com 2010-09-03 00:02 ------- > Without having seriously looked into your code, I note that two completely > different, closed source compilers (ICC and SunStudio) leads to the same > behavior as GCC at runtime. Does your code actually "work" (behaves like you > expect) somewhere? > > >
Fair enough, but first blush I also don't see any text in the C++ Standard guaranteeing the behavior you want, wondered if you actually can get it with other compilers, maybe as implementation defined. Somebody else will properly triage this PR, anyway...
union { unsigned int a : 1, b : 4; unsigned int data; }; This is an union of three elements each over lapping, that is a:1 overlaps with b:4 and data. So this is expected behavior as far as I can tell.
You can use a GCC extension of anonymous structs: struct bfa { union { struct { unsigned int a : 1, b : 4; }; unsigned int data; }; }; To get the behavior you want.
Subject: Re: Bug with anonymous unions and bit-fields Wow, So there is a diff inside and outside a struct? This is very counter-intuitive but I am to accept your explanation if that's what the language says. Thanks so much for looking into it and responding. Sorry if it is not a bug, I googled for anything similar before filing it. -Runip On 02-Sep-2010, at 6:11 PM, pinskia at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> wrote: > > > ------- Comment #5 from pinskia at gcc dot gnu dot org 2010-09-03 01:10 ------- > union { > unsigned int a : 1, > b : 4; > unsigned int data; > }; > > > This is an union of three elements each over lapping, that is a:1 overlaps with > b:4 and data. So this is expected behavior as far as I can tell. > > > -- > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45510 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter. >
If you look at the actual Standard, both alignment and allocation of bit-fields are implementation defined. Thus, as far as I can see, at best we are talking about non-portable implementation defined behavior. If you want my advice, try to stay away from those tricks, with and without anonymous struct.
Subject: Re: Bug with anonymous unions and bit-fields Thank you so much. You can close this bug if you wish. -Runip On 03-Sep-2010, at 3:47 AM, paolo dot carlini at oracle dot com <gcc-bugzilla@gcc.gnu.org> wrote: > > > ------- Comment #8 from paolo dot carlini at oracle dot com 2010-09-03 10:46 ------- > If you look at the actual Standard, both alignment and allocation of bit-fields > are implementation defined. Thus, as far as I can see, at best we are talking > about non-portable implementation defined behavior. If you want my advice, try > to stay away from those tricks, with and without anonymous struct. > > > -- > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45510 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter. >
Subject: Re: Bug with anonymous unions and bit-fields Your suggestion works: struct bfc { union { struct { unsigned int a : 1, b : 4; }; unsigned int data; }; }; void testc() { cout << __func__ << endl; bfc bf0; bf0.data = 0; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << bf0.b << endl; bf0.a = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << hex << bf0.b << endl; bf0.b = 1; cout << "bf0.data=" << hex << bf0.data << endl; cout << "bf0.a=" << bf0.a << endl; cout << "bf0.b=" << hex << bf0.b << endl; } Output is .... testc bf0.data=0 bf0.a=0 bf0.b=0 bf0.data=1 bf0.a=1 bf0.b=0 bf0.data=3 bf0.a=1 bf0.b=1 ----------------------------------------------------------------------------------- I guess the fundamental issue which confused me was: struct bfa { union { unsigned int a : 1, b : 4; unsigned int data; }; }; that it appeared to be a union of 2 integers (one bit-field) rather than the implementation version where the union is of 3 integers (two-bitfields). If the standard does not say anything specific about it, then I guess the compiler is free to do whatever it wants. In fact, I tried a slight variation on bfa, where I tried to force alignment on the first integer packing. struct bfd { union { unsigned int a : 1, b : 4, : 0; //force alignment unsigned int data; }; }; However this gives the same result as bfa. So I guess semantically it is very confusing to a user. Perhaps this part of the language should be tightened. Thanks Paolo! -Runip paolo dot carlini at oracle dot com wrote: > ------- Comment #8 from paolo dot carlini at oracle dot com 2010-09-03 10:46 ------- > If you look at the actual Standard, both alignment and allocation of bit-fields > are implementation defined. Thus, as far as I can see, at best we are talking > about non-portable implementation defined behavior. If you want my advice, try > to stay away from those tricks, with and without anonymous struct. > > >
I don't see anything confusing about it. If you have: union { int a, b, c; } u; u.a overlaps u.b and u.c as well, and the same applies to bitfields. union isn't struct, see ISO C99 6.7.2.1/5. The standard is clear on this.
Subject: Re: Bug with anonymous unions and bit-fields Okay, I guess I was confused by "struct or union" semantics. Thanks! jakub at gcc dot gnu dot org wrote: > ------- Comment #11 from jakub at gcc dot gnu dot org 2010-09-03 20:53 ------- > I don't see anything confusing about it. If you have: > union { int a, b, c; } u; > u.a overlaps u.b and u.c as well, and the same applies to bitfields. union > isn't struct, see ISO C99 6.7.2.1/5. The standard is clear on this. > > >