Page 1 of 1
Undefined behaviour? (c++)
Posted: Mon Sep 17, 2007 1:32 pm
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.
Posted: Mon Sep 17, 2007 2:03 pm
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.
Posted: Mon Sep 17, 2007 2:05 pm
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.
Posted: Mon Sep 17, 2007 2:19 pm
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.
Posted: Mon Sep 17, 2007 2:28 pm
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?
Posted: Mon Sep 17, 2007 4:49 pm
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.
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.
Posted: Mon Sep 17, 2007 5:37 pm
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...
Posted: Tue Sep 18, 2007 12:03 am
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.
Posted: Tue Sep 18, 2007 3:52 am
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.
Posted: Tue Sep 18, 2007 7:26 am
by Smilediver
Kevin McGuire wrote:x86 GCC 3.4.4 is 4 bytes.
x86 GCC 4.1.2 is 1 bytes.
Actually - WOW
I haven't been expecting a result like this.
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?
Posted: Tue Sep 18, 2007 1:32 pm
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.
Posted: Tue Sep 18, 2007 1:59 pm
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.
Posted: Tue Sep 18, 2007 2:29 pm
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).
Posted: Tue Sep 18, 2007 2:52 pm
by Zacariaz
seems to work. thanks.
Posted: Wed Sep 19, 2007 5:08 am
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!