GET THE SIZE of struct in the PREPROCESSOR

R

requinham

Hello,

i have a structure in my program and i want generate a compile error
when the size of structure is not pow of two.

my problem is that i don't found the way to get the size of structure
in preprocessor mode and it's necessary to generate a COMPILE ERROR
when the size of my struct is not pow of 2 :(

thank you
 
I

ImpalerCore

G

Gene

Hello,

i have a structure in my program and i want generate a compile error
when the size of structure is not pow of two.

my problem is that i don't found the way to get the size of structure
in preprocessor mode and it's necessary to generate a COMPILE ERROR
when the size of my struct is not pow of 2 :(

thank you

The preprocessor works on the program as text only. It doesn't have
any information about structure sizes. The kind of check you are
after is typically checked in a configure script by compiling,
running, and checking the return value or output of a small program in
preparation for a build. Something like

#include "mystruct.h"

int main(void)
{
size_t test_size = 1;

while (test_size != 0) {
if (test_size == sizeof(MYSTRUCT)) {
return 0;
test_size <<= 1;
}
return 1;
}
 
E

Eric Sosman

Hello,

i have a structure in my program and i want generate a compile error
when the size of structure is not pow of two.

my problem is that i don't found the way to get the size of structure
in preprocessor mode and it's necessary to generate a COMPILE ERROR
when the size of my struct is not pow of 2 :(

The preprocessor cannot get the size of anything, not
even of a char, because the preprocessor operates at a time
before things like `char' have acquired any meaning: They're
just tokens ("preprocessing tokens," actually), and their
eventual effect of declaring types that have sizes is still
in the future.

However, you can cause compilation errors at a later
stage. One way is to declare an array type whose dimension
is invalid if the condition you're interested in doesn't hold:

char foo[ (sizeof(struct s) & (sizeof(struct s)-1)) == 0 ];

If the condition holds this is `char foo[1];' and valid; if the
condition doesn't hold it's `char foo[0];' which is invalid and
should generate a diagnostic. (Unfortunately, some compilers
fail to diagnose zero-dimension arrays; to get diagnostics even
from them you could use `char foo[... == 0 ? 1 : -1];' instead.)

The diagnostic will probably say something about the invalid
array dimension, rather than something helpful about the fact
that sizeof(struct s) isn't a power of two. One thing you can
do about that is use a comment:

/* If the compiler objects to the following declaration,
* the problem is that sizeof(struct s) should be a power
* of two but is not.
*/
char foo[...];

The person who investigates the funny-looking compiler complaint
will presumably arrive at the offending declaration of foo, and
will then see the comment that explains what's *really* wrong.

You don't have to use an array dimension as the thing the
compiler will object to. For example, you could declare a struct
having a bit-field whose width is given by the test expression
(note that `:0' *is* valid as a bit-field width, so make sure
the evaluation produces a negative number on failure).
 
R

requinham

i have a structure in my program and i want generate a compile error
when the size of structure is not pow of two.
my problem is that i don't found the way to get the size of structure
in preprocessor mode and it's necessary to generate a COMPILE ERROR
when the size of my struct is not pow of 2 :(

     The preprocessor cannot get the size of anything, not
even of a char, because the preprocessor operates at a time
before things like `char' have acquired any meaning: They're
just tokens ("preprocessing tokens," actually), and their
eventual effect of declaring types that have sizes is still
in the future.

     However, you can cause compilation errors at a later
stage.  One way is to declare an array type whose dimension
is invalid if the condition you're interested in doesn't hold:

        char foo[ (sizeof(struct s) & (sizeof(struct s)-1)) == 0 ];

If the condition holds this is `char foo[1];' and valid; if the
condition doesn't hold it's `char foo[0];' which is invalid and
should generate a diagnostic.  (Unfortunately, some compilers
fail to diagnose zero-dimension arrays; to get diagnostics even
from them you could use `char foo[... == 0 ? 1 : -1];' instead.)

     The diagnostic will probably say something about the invalid
array dimension, rather than something helpful about the fact
that sizeof(struct s) isn't a power of two.  One thing you can
do about that is use a comment:

        /* If the compiler objects to the following declaration,
         * the problem is that sizeof(struct s) should be a power
         * of two but is not.
         */
        char foo[...];

The person who investigates the funny-looking compiler complaint
will presumably arrive at the offending declaration of foo, and
will then see the comment that explains what's *really* wrong.

     You don't have to use an array dimension as the thing the
compiler will object to.  For example, you could declare a struct
having a bit-field whose width is given by the test expression
(note that `:0' *is* valid as a bit-field width, so make sure
the evaluation produces a negative number on failure).

this is a good idea and i have receive a solution from a friend
Alexander :

#define CHECK_SIZE_POW2(a) ((a) && !((a) & ((a)-1)))
#define SIZE_IS_POW_OF_TWO(x) ( CHECK_SIZE_POW2(sizeof(x)))//
#define STATIC_ASSERT(b) int _static_assert[ b ? 1 : -1 ];

// Usage:

typedef struct Foo
{
unsigned int a;
unsigned char b;
unsigned char c[24];
}foo;

STATIC_ASSERT(SIZE_IS_POW_OF_TWO(Foo));


what is your opinion ?
 
E

Eric Sosman

[... declare an invalidly-sized array to provoke diagnostics ...]

this is a good idea and i have receive a solution from a friend
Alexander :

#define CHECK_SIZE_POW2(a) ((a)&& !((a)& ((a)-1)))
#define SIZE_IS_POW_OF_TWO(x) ( CHECK_SIZE_POW2(sizeof(x)))//
#define STATIC_ASSERT(b) int _static_assert[ b ? 1 : -1 ];

// Usage:

typedef struct Foo
{
unsigned int a;
unsigned char b;
unsigned char c[24];
}foo;

STATIC_ASSERT(SIZE_IS_POW_OF_TWO(Foo));

what is your opinion ?

There are two problems with using the name `_static_assert'.
First, it's a reserved identifier in many contexts, and may run
afoul of the implementation's own machinery. Second, using the
same name every time means you can use it only once per scope.
If you use it at file scope (where it will have external linkage),
you can use it only once in the entire program, no matter how
many separately-compiled modules it contains.

There are other miscellaneous issues. I'd suggest putting
parentheses around the `b' in the expansion of STATIC_ASSERT.
The first test in CHECK_SIZE_POW2 is unnecessary if you know
the macro will be used only with sizes (necessarily non-zero).
I think SIZE_IS_POW_OF_TWO adds more verbosity than value. And
finally, `foo' is not `Foo' ...
 
E

Ersek, Laszlo

Eric Sosman said:
On 3/4/2010 5:33 PM, requinham wrote:
#define STATIC_ASSERT(b) int _static_assert[ b ? 1 : -1 ];
using the
same name every time means you can use it only once per scope.
If you use it at file scope (where it will have external linkage),
you can use it only once in the entire program, no matter how
many separately-compiled modules it contains.

I've seen a static assert macro somewhere that pasted __LINE__ and also
used the "typedef" storage-class-specifier, so that the identifier has
no linkage and doesn't declare (let alone define) any object.

#define CAT(x, y) x ## y
#define CAT2(x, y) CAT(x, y)
#define STATIC_ASSERT(x) \
typedef char CAT2(static_assert_line_, __LINE__)[!(x) ? -1 : 1]

Or something like that.

Cheers,
lacos
 
S

Seebs

#define CHECK_SIZE_POW2(a) ((a) && !((a) & ((a)-1)))
#define SIZE_IS_POW_OF_TWO(x) ( CHECK_SIZE_POW2(sizeof(x)))//
#define STATIC_ASSERT(b) int _static_assert[ b ? 1 : -1 ];

// Usage:

typedef struct Foo
{
unsigned int a;
unsigned char b;
unsigned char c[24];
}foo;

STATIC_ASSERT(SIZE_IS_POW_OF_TWO(Foo));

what is your opinion ?

My opinion is that this is a VERY BAD IDEA.

Why? Because it means that the error message you get will be *meaningless*
to the user. It frequently results in an error message being assigned to
a meaningless location in the middle of nowhere, with no real explanation
of what the intended context was.

Start from the top. Why do you believe that this must be a power of two?
It seems as though you would be fine with padding it out. Why not just pad
it out to the next power of two in your source?

-s
 
M

Michael Tsang

requinham said:
Hello,

i have a structure in my program and i want generate a compile error
when the size of structure is not pow of two.

my problem is that i don't found the way to get the size of structure
in preprocessor mode and it's necessary to generate a COMPILE ERROR
when the size of my struct is not pow of 2 :(

thank you

Don't multi-post. Cross-post instead.
 
R

requinham

[... declare an invalidly-sized array to provoke diagnostics ...]
this is a good idea and i have receive a solution from a friend
Alexander  :
#define CHECK_SIZE_POW2(a) ((a)&&  !((a)&  ((a)-1)))
#define SIZE_IS_POW_OF_TWO(x)  ( CHECK_SIZE_POW2(sizeof(x)))//
#define STATIC_ASSERT(b) int _static_assert[ b ? 1 : -1 ];
// Usage:
typedef struct Foo
{
   unsigned int a;
   unsigned char b;
   unsigned char c[24];
}foo;
STATIC_ASSERT(SIZE_IS_POW_OF_TWO(Foo));

what is your opinion ?

     There are two problems with using the name `_static_assert'.
First, it's a reserved identifier in many contexts, and may run
afoul of the implementation's own machinery.  Second, using the
same name every time means you can use it only once per scope.
If you use it at file scope (where it will have external linkage),
you can use it only once in the entire program, no matter how
many separately-compiled modules it contains.

     There are other miscellaneous issues.  I'd suggest putting
parentheses around the `b' in the expansion of STATIC_ASSERT.
The first test in CHECK_SIZE_POW2 is unnecessary if you know
the macro will be used only with sizes (necessarily non-zero).
I think SIZE_IS_POW_OF_TWO adds more verbosity than value.  And
finally, `foo' is not `Foo' ...

But how can i do to specify my error message to the compiler :(
 
N

Noob

Seebs said:
Start from the top. Why do you believe that this must be a power of two?
It seems as though you would be fine with padding it out. Why not just pad
it out to the next power of two in your source?

How would one do that?

struct foo
{
double x;
int i;
unsigned char pad[N];
};

How can one (portably) choose N so that sizeof(struct foo)
is a power of two?

Regards.
 
K

Keith Thompson

Noob said:
Seebs said:
Start from the top. Why do you believe that this must be a power of two?
It seems as though you would be fine with padding it out. Why not just pad
it out to the next power of two in your source?

How would one do that?

struct foo
{
double x;
int i;
unsigned char pad[N];
};

How can one (portably) choose N so that sizeof(struct foo)
is a power of two?

Here's one way that should work (though it's not *strictly* portable):

struct dummy {
double x;
int i;
unsigned char pad[16];
};

struct foo {
double x;
int i;
unsigned char pad[some_expression];
};

where some_expression refers to offsetof(dummy, pad). (I'm too
lazy to work out the details.)

I chose 16 to be big enough that the alignment of pad in struct
dummy and in struct foo is likely to be the same. unsigned char[N]
only *requires* 1-byte alignment, but a compiler might choose a
stricter alignment. If you're really paranoid, declare a union to
guarantee that the initial subsequences have the same layout.
 
S

Seebs

How would one do that?
Easily.

struct foo
{
double x;
int i;
unsigned char pad[N];
};

How can one (portably) choose N so that sizeof(struct foo)
is a power of two?

One can't.

And one doesn't need to, ever.

struct foo { double x; int i; }

static size_t foosize = 0;

void
get_foosize(void) {
if (!foosize) {
size_t newsize = 1;
while (newsize < sizeof(struct foo))
newsize <<= 1;
}
}

struct foo *
new_foo(void) {
get_foosize();
return calloc(foosize, 1);
}

You don't have to actually make the object be that size. Just allocate,
copy, and otherwise modify objects of the next power of two size larger.
No one cares what size the actual struct is! All you need to do is manipulate
chunks of storage of the size you need, which is at least big enough for
the object. It's not an error to allocate a region bigger than you need.

-s
 

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

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top