Compiler error for "wrong" sized type

D

David White

The size of a struct can be affected by compiler packing. Suppose you need it to be a
specific value for some reason (e.g., in firmware). How can you get the compiler to
generate an error for the wrong size rather than assert it at run-time? Here is one way,
but I don't know if it's guaranteed to work on any compiler:
1/(sizeof(struct my_struct) == correct_size);

For me, the above produces a compile-time divide-by-zero error for the wrong size. Is
there a better way?

DW
 
R

Richard Heathfield

David White said:
The size of a struct can be affected by compiler packing. Suppose you need
it to be a specific value for some reason (e.g., in firmware). How can you
get the compiler to generate an error for the wrong size rather than
assert it at run-time? Here is one way, but I don't know if it's
guaranteed to work on any compiler: 1/(sizeof(struct my_struct) ==
correct_size);

For me, the above produces a compile-time divide-by-zero error for the
wrong size. Is there a better way?

Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 - 1];

If the struct is the wrong size, this will yield a negatively sized array,
which is illegal.
 
T

Tomás

David White posted:
The size of a struct can be affected by compiler packing. Suppose you
need it to be a specific value for some reason (e.g., in firmware). How
can you get the compiler to generate an error for the wrong size rather
than assert it at run-time? Here is one way, but I don't know if it's
guaranteed to work on any compiler: 1/(sizeof(struct my_struct) ==
correct_size);

For me, the above produces a compile-time divide-by-zero error for the
wrong size. Is there a better way?

DW


To eliminate the padding (i.e. store each member exactly where you want it),
you could use pointer trickery.

For example, instead of having:

typedef struct Monkey {
int i;
char b;
int j;
};

You could have the following. (It's not pretty, but you could clean it up
and give it a nice interface).


typedef char Monkey[ 2 * sizeof(int) + 1 ];


And then you have functions to access each member:

void SetI( Monkey* const m, int const val )
{
*( (int*)m ) = val;
}

int GetI( const Monkey* const m )
{
return *( (const int*)m );
}

void SetB( Monkey* const m, char const val )
{
*( (char*)m + sizeof(int) ) = val;
}

char GetB( const Monkey* const m )
{
return *( (const char*)m + sizeof(int) );
}

void SetJ( Monkey* const m, int const val )
{
*( (int*)( (char*)m + sizeof(int) + 1 ) ) = val;
}

int GetJ( const Monkey* const m )
{
return *( (const int*)( (const char*)m + sizeof(int) + 1 ) );
}


-Tomás
 
K

Keith Thompson

Tomás said:
To eliminate the padding (i.e. store each member exactly where you want it),
you could use pointer trickery.

For example, instead of having:

typedef struct Monkey {
int i;
char b;
int j;
};

You could have the following. (It's not pretty, but you could clean it up
and give it a nice interface).


typedef char Monkey[ 2 * sizeof(int) + 1 ];


And then you have functions to access each member: [snip]
void SetJ( Monkey* const m, int const val )
{
*( (int*)( (char*)m + sizeof(int) + 1 ) ) = val;
}

int GetJ( const Monkey* const m )
{
return *( (const int*)( (const char*)m + sizeof(int) + 1 ) );
}

This access a misaligned int. On many systems, it will cause a trap.
 
B

Bill Pursell

Tomás wrote(in reference to structure padding):
To eliminate the padding (i.e. store each member exactly where you want it),
you could use pointer trickery.

As I read that, the following thought actually fleetingly crossed my
mind:
"That's quite elegant, and eliminates all those annoying padding
problems. Why did C ever bother with the syntactic sugar of structures
and dereferencing members by name?"

I need psychiatric assistance. :)
 
D

David White

Richard said:
Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 -
1];

If the struct is the wrong size, this will yield a negatively sized
array, which is illegal.

Thanks. That's an improvement. Unfortunately, our Hi-Tech compiler doesn't pick it up
because it treats an array size of -1 as unsigned!

DW

P.S. A colleague is terribly disappointed to learn that an array cannot have a negative
size. He thinks it should be allowed, with the valid index range extending from size+1 to
zero inclusive (e.g., -9 to 0 for a size of -10). I asked him what he would expect for a
sizeof of such an array, but he can't decide whether it should be positive or negative.
 
D

David White

David said:
with the
valid index range extending from size+1 to zero inclusive (e.g., -9
to 0 for a size of -10).

Make that: size to -1 inclusive (e.g., -10 to -1 for a size of -10).

DW
 
N

Nick Keighley

David said:
The size of a struct can be affected by compiler packing. Suppose you need it to be a
specific value for some reason (e.g., in firmware). How can you get the compiler to
generate an error for the wrong size rather than assert it at run-time? Here is one way,
but I don't know if it's guaranteed to work on any compiler:
1/(sizeof(struct my_struct) == correct_size);

For me, the above produces a compile-time divide-by-zero error for the wrong size. Is
there a better way?

normally I speak against the Evil of "#prgama pack" and its ilk. Many
compilers
have extensions that tell the compiler to remove packing from specified
structs.
Such extensions are inherently non-portable and you should be very wary
you
don't assign packed to unpacked or vice versa. But for access to
firmware
especially embedded systems I think it can be justified. Embedded
compilers
may be more likely to support such extensions.
 
R

Richard Heathfield

David White said:
I asked him what he would expect for a sizeof of such an array, but
he can't decide whether it should be positive or negative.

The size of an array is equal to the number of elements times the size of
each element. Thus, even an array with completely negative indices (were
such an array legal) would have a positive size. Your plane doesn't
suddenly acquire negative weight when you fly across the equator. (It may,
however, flip upside down, depending on who wrote your fbws!)
 
D

David White

Nick Keighley said:
normally I speak against the Evil of "#prgama pack" and its ilk. Many
compilers
have extensions that tell the compiler to remove packing from specified
structs.
Such extensions are inherently non-portable and you should be very wary
you
don't assign packed to unpacked or vice versa. But for access to
firmware
especially embedded systems I think it can be justified. Embedded
compilers
may be more likely to support such extensions.

I also direct my compiler to use zero padding if I need to create literally
millions of instances of a small struct, e.g., in a recursive puzzle-solving
algorithm that generates new states exponentially and the number needed is
unknown, and may exceed available memory. Undesirable as they may be, such
extensions are useful or necessary in some cases (as are other quite nasty
non-standard practices on occasion).

DW
 
E

Eric Sosman

David said:
Richard said:
Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 -
1];

If the struct is the wrong size, this will yield a negatively sized
array, which is illegal.


Thanks. That's an improvement. Unfortunately, our Hi-Tech compiler doesn't pick it up
because it treats an array size of -1 as unsigned!

DW

P.S. A colleague is terribly disappointed to learn that an array cannot have a negative
size. He thinks it should be allowed, with the valid index range extending from size+1 to
zero inclusive (e.g., -9 to 0 for a size of -10). I asked him what he would expect for a
sizeof of such an array, but he can't decide whether it should be positive or negative.

Wow! You're a colleague of Paul Dirac?

Hmmm: Dirac's ideas could revolutionize memory management in
C-- (or would it be --C?). If "no memory at all" spontaneously
split into a chunk of allocated memory and a corresponding chunk
of unallocated anti-memory, a program could store data in the
allocated area without needing to call malloc(). Of course, one
would need to be careful: pointer aliasing could cause the memory
and anti-memory to come together and undergo mutual annihilation,
with the resulting, er, Gamma ray constituting an implementation-
defined signal. The task of keeping the allocation separated
from the anti-allocation is probably best left to Maxwell's Nasal
Demon.
 
K

Kenneth Brody

David White wrote:
[...]
P.S. A colleague is terribly disappointed to learn that an array cannot
have a negative size. He thinks it should be allowed, with the valid
index range extending from size+1 to zero inclusive (e.g., -9 to 0 for
a size of -10). I asked him what he would expect for a sizeof of such
an array, but he can't decide whether it should be positive or negative.

http://astronomy.swin.edu.au/~pbourke/geometry/minus1.html

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
T

tedu

David said:
Richard said:
Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 -
1];

If the struct is the wrong size, this will yield a negatively sized
array, which is illegal.

Thanks. That's an improvement. Unfortunately, our Hi-Tech compiler doesn't pick it up
because it treats an array size of -1 as unsigned!

does it allow multiple case statements with the same value?

switch (0) {
case sizeof(struct my_struct) == correct_size:
case 0:
}
 
S

S.Tobias

tedu said:
David said:
Richard said:
Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 -
1];

If the struct is the wrong size, this will yield a negatively sized
array, which is illegal.

Thanks. That's an improvement. Unfortunately, our Hi-Tech compiler doesn't pick it up
because it treats an array size of -1 as unsigned!

does it allow multiple case statements with the same value?

switch (0) {
case sizeof(struct my_struct) == correct_size:
case 0:
}
Nit: a label reqires a following statement; make it:
switch (0) {
case sizeof(struct my_struct) == correct_size: ;
case 0: ;
}

(Otherwise it's a nice trick, I liked it.)
 
G

Guest

S.Tobias said:
tedu said:
David said:
Richard Heathfield wrote:
Well, I don't know about "better", but I like this:

char DetectWrongSize[(sizeof(struct my_struct) == correct_size) * 2 -
1];

If the struct is the wrong size, this will yield a negatively sized
array, which is illegal.

Thanks. That's an improvement. Unfortunately, our Hi-Tech compiler doesn't pick it up
because it treats an array size of -1 as unsigned!

does it allow multiple case statements with the same value?

switch (0) {
case sizeof(struct my_struct) == correct_size:
case 0:
}
Nit: a label reqires a following statement; make it:
switch (0) {
case sizeof(struct my_struct) == correct_size: ;
case 0: ;
}

(Otherwise it's a nice trick, I liked it.)

"case 0: ;" is a statement, so the first semicolon isn't necessary. The
second indeed is though.
 
D

David White

tedu said:
does it allow multiple case statements with the same value?

I don't know. I'll find out next week.
switch (0) {
case sizeof(struct my_struct) == correct_size:
case 0:
}

Good idea. Incidentally, I had a problem with this rule once. I allowed two
different characters in encoded text to have the same meaning, e.g.,
#define TOKEN_CHAR '#'
#define ALT_TOKEN_CHAR 't'

Since they have the same meaning, the switch that processed them looked like
this:
switch(ch)
{
....
case TOKEN_CHAR:
case ALT_TOKEN_CHAR:
/* process */
break;
....
}

But in some cases I didn't want to allow both characters, so I did this:
#define TOKEN_CHAR '#'
#define ALT_TOKEN_CHAR '#'

The switch then wouldn't compile, but it could have, since there's no clash.

DW
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top