Undefined behaviour? (c++)

Programming, for all ages and all languages.
Post Reply
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Undefined behaviour? (c++)

Post by Zacariaz »

Being the perfectionist i am (all though it is not allways obvious) it illudes me how i could not have thought of this before.
I just ,ade a test which had the expected outcome:

Code: Select all

struct T0 {bool a  ,b  ,c  ,d  ,e  ,f  ,g  ,h  ;}; /* sizeof(T0) == 8 */
struct T1 {bool a:1,b:1,c:1,d:1,e:1,f:1,g:1,h:1;}; /* sizeof(T1) == 1 */
Now the question is if this behavior is to rely on.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

Depends on what you mean. Yes, a bitfield takes less space than a series of bool, on average (because, on most machines, _Bool is merely a typedef to char or int). However, it is up to the implementation if your struct T1 does take one byte, two byte, four byte, or 5.67837 bytes of actual memory.
Every good solution is obvious once you've found it.
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

but when sizeof() tell me that it take up x bytes, then i can rely on it?

edit:
one last thing, is it possible to use bitfields on arrays? I have yet to find out how if it is.
Smilediver
Member
Member
Posts: 37
Joined: Sun Aug 05, 2007 4:23 pm

Post by Smilediver »

sizeof() will always return the size of the type. But bit field actual sizes and alignment are depended on implementation, so it would be unsafe to assume sizeof(T1) == 1. If you are assuming so, then add checks for this at the application startup. Just in case of the worst case scenario.
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

Trinka wrote:sizeof() will always return the size of the type. But bit field actual sizes and alignment are depended on implementation, so it would be unsafe to assume sizeof(T1) == 1. If you are assuming so, then add checks for this at the application startup. Just in case of the worst case scenario.
That was what i thought, but how else can it be tested?
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Post by jnc100 »

Zacariaz wrote:That was what i thought, but how else can it be tested?
configure scripts compile a small test case to check the size of various types, e.g.

Code: Select all

int main() { return sizeof(T1); }
then parse the return value in a shell script and #define a macro to it in config.h so you know the size in your actual program. Is there any other sort of testing you were thinking about?

Regards,
John.
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

eh, never mind then... i dont understand a word... but thats ok, i got the most important part of the answer, the rest i can worry about later...
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

"Traditionally", the building of an application is done in three steps:

Code: Select all

$ ./configure
$ make
$ make install
The first step, the "configure" script, can be used to do the things jnc100 described: Trying things, and writing the results as #define statements in some header, so you can include that header in your code and act on the findings of the configure script.
Every good solution is obvious once you've found it.
User avatar
Kevin McGuire
Member
Member
Posts: 843
Joined: Tue Nov 09, 2004 12:00 am
Location: United States
Contact:

Post by Kevin McGuire »

If you are pedantic about it then you might also want to check that you actually get the performance benefit you are expecting. And, that you do not access the structure in any way such as casting it which would cause it to become non-portable like Solar and Trinka said.

A example is the compiling using GCC 3.4.4 or 4.1.2.

Code: Select all

struct T1 {
	bool a:1,b:1,c:1,d:1,e:1,f:1,g:1,h:1;
};
int main(void)
{
  printf("sizeof:%u\n", sizeof(struct T1));
  return 1;
}
x86 GCC 3.4.4 is 4 bytes.
x86 GCC 4.1.2 is 1 bytes.
Smilediver
Member
Member
Posts: 37
Joined: Sun Aug 05, 2007 4:23 pm

Post by Smilediver »

Kevin McGuire wrote:x86 GCC 3.4.4 is 4 bytes.
x86 GCC 4.1.2 is 1 bytes.
Actually - WOW :shock: I haven't been expecting a result like this. :o

Also, it's probably a good idea to use __attribute__((__packed__)), but I'm not sure if this would help. Kevin, want to try that? ;-)
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

Trinka wrote:sizeof() will always return the size of the type. But bit field actual sizes and alignment are depended on implementation, so it would be unsafe to assume sizeof(T1) == 1. If you are assuming so, then add checks for this at the application startup.
Or use a trick to assert it at compile time:

Code: Select all

// code hidden in some header
template <int a, int b> struct are_equal { enum { value = false }; };
template <int a> struct are_equal<a, a> { enum { value = true }; };

template <bool value> class assert_true;
template <> class assert_true<true> {};

// code in your program
static assert_true<are_equal<1, sizeof(struct T1)>::value> check_if_the_bitfield_works;
If your struct is 1, the value in the are_equal class define will be 1, the assert_true class will be defined (as shown above) and it will compile to a harmless unused global variable, which is optimized out entirely. If your struct is not 1 byte, it will be false, the class won't exist and you'll get a warning for an object with the name "check_if_the_bitfield_works" with the error that its class isn't defined.
Last edited by Candy on Tue Sep 18, 2007 2:32 pm, edited 1 time in total.
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

Candy wrote:
Trinka wrote:sizeof() will always return the size of the type. But bit field actual sizes and alignment are depended on implementation, so it would be unsafe to assume sizeof(T1) == 1. If you are assuming so, then add checks for this at the application startup.
Or use a trick to assert it at compile time:

Code: Select all

// code hidden in some header
template <int a, int b> struct are_equal { enum { value = false; } };
template <int a> struct are_equal<a, a> { enum { value = true; } };

template <bool value> class assert_true;
template <> class assert_true<true> {};

// code in your program
static const assert_true<are_equal<1, sizeof(struct T1)>::value> check_if_the_bitfield_works;
If your struct is 1, the value in the are_equal class define will be 1, the assert_true class will be defined (as shown above) and it will compile to a harmless unused global variable, which is optimized out entirely. If your struct is not 1 byte, it will be false, the class won't exist and you'll get a warning for an object with the name "check_if_the_bitfield_works" with the error that its class isn't defined.
Have you tested this code? I think maybe a couble of ';'s are missing after the enum declarations, but even with that fixed i cant get it to work.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

Zacariaz wrote:Have you tested this code? I think maybe a couble of ';'s are missing after the enum declarations, but even with that fixed i cant get it to work.
As usual, I don't test my submissions. The theory is more important to understand than the copy-paste.

Sec.

Move the semicolons from after true and false to after the }, remove const from the definition (since it's static anyway, it'll be optimized away anyway).
User avatar
Zacariaz
Member
Member
Posts: 1069
Joined: Tue May 22, 2007 2:36 pm
Contact:

Post by Zacariaz »

seems to work. thanks.
Smilediver
Member
Member
Posts: 37
Joined: Sun Aug 05, 2007 4:23 pm

Post by Smilediver »

Candy wrote:
Trinka wrote:sizeof() will always return the size of the type. But bit field actual sizes and alignment are depended on implementation, so it would be unsafe to assume sizeof(T1) == 1. If you are assuming so, then add checks for this at the application startup.
Or use a trick to assert it at compile time:

Code: Select all

// code hidden in some header
template <int a, int b> struct are_equal { enum { value = false }; };
template <int a> struct are_equal<a, a> { enum { value = true }; };

template <bool value> class assert_true;
template <> class assert_true<true> {};

// code in your program
static assert_true<are_equal<1, sizeof(struct T1)>::value> check_if_the_bitfield_works;
If your struct is 1, the value in the are_equal class define will be 1, the assert_true class will be defined (as shown above) and it will compile to a harmless unused global variable, which is optimized out entirely. If your struct is not 1 byte, it will be false, the class won't exist and you'll get a warning for an object with the name "check_if_the_bitfield_works" with the error that its class isn't defined.
Nice! I always wondered if it's possible to test the sizeof() during compile time instead of runtime. Thanks!
Post Reply