In AIX during compilation of header file i am facing this issue.
Header file (header1.h) has the structure like this:
struct Str { int aa; char bb; };
now in .c file including header1.h
#include<stdio.h> #include"f1.h" #define DEF(x) (&sx1.x -&sx1.a) static struct MyStruct{ struct Str a; struct Str c; struct Str b; }sx1 = {DEF(b),'B','A'}; int main() { printf("%d %c",sx1.a,sx1.b); }
when i’m compiling the above .c file using xlc compiler it is throwing the error:
header1.h”, line xxxx: 1506-221 (S) Initializer must be a valid constant expression.
make: 1254-004 The error code from the last command is 1.
Stop.
Advertisement
Answer
Well, you have several mistakes, apart from the one you are telling. First of all, you are enclosing (and that’s very dangerous, because you are hiding the expressions below macro instantiations and that makes errors invisible to you) in the DEF
macro the subtraction of addresses with different pointer types (which is illegal) For example, if you redefine DEF
to work for your first struct
as:
#define DEF(f) (&sx1.f - &sx1.aa)
then you’ll get an error in the expansion of:
DEF(bb) -> (&sx1.bb - &sx1.aa)
where bb
is a char
and a
is an int
(you’ll be subtracting a int *
to a char *
). This will lead to compilation problems after the expansion of the DEF
macro, but you will not see the actual expansion that produces the compiler error.
Second, an initialiser can only use constant expressions, this means, static expressions that produce only constants or expressions of constants, and &
operator has to be resolved at link time most times (this makes the expression not a constant one, but something that can change between compilations) and even at runtime (assume the operand to the first &
is a stack automatic variable, and he operand to the second is a global, fixed variable, then each time you initialise, the constant value is different, depending on how did the stack grew at runtime. You cannot use the &
operator in a constant expression as a general rule.
Third, if you are trying to emulate the definition of the ANSI offsetof(structure_type, field)
macro, then you can use something like (beware that this definition leads to some tricks that can be architecture dependant, and for that reason not be portable):
#define OFFSETOF(type, field) ((size_t)(char *)(&((type*)0)->field))
as in the following code:
pru.c
#include <stdio.h> struct my_data_struct { int a; char b; double c; char d[100]; int e; }; #define OFFSET_OF(type, field) ((size_t)(char *)(&((type*)0)->field)) int main() { #define P(f) printf("OFFSET_OF(struct my_data_struct, %s) == %zun", #f, OFFSET_OF(struct my_data_struct, f)) P(a); P(b); P(c); P(d); P(e); }
that produces:
$ run pru OFFSET_OF(struct my_data_struct, a) == 0 OFFSET_OF(struct my_data_struct, b) == 4 OFFSET_OF(struct my_data_struct, c) == 8 OFFSET_OF(struct my_data_struct, d) == 16 OFFSET_OF(struct my_data_struct, e) == 116 $ _
on my system.
Explanation
(type*)0
is the address of the NULL
literal converted to (type*)
((type*)0)->field
is the null pointer dereferenced at its field field
(don’t worry, as we aren’t actually dereferencing the value, only getting a reference to it)
&((type*)0)->field
is its address.
(char *)(&((type*)0)->field)
is the address converted to a (char *)
(so pointer arithmetic is byte size). And
((size_t)(char *)(&((type*)0)->field)
is the address converted to a size_t
value.
Of course, part (if not most) of this calculation is architecture dependant, and that’s the reason the standard today includes some kind of this macro in the standard library (#include <stddef.h>
). So don’t use my definition (just in case you don’t have it in your system) and search your compiler/library documentation for an offsetof
macro that shows you the position of fields in a structure.
One last thing… as I’ve used a constant pointer value (everything derives from the constant 0
) and have not subtracted references, it is usable in initialiser that require constant expressions.
#include <stdio.h> struct my_data_struct { int a; char b; double c; char d[100]; int e; }; #define OFFSET_OF(type, field) ((size_t)(char *)(&((type*)0)->field)) static size_t my_vector[] = { OFFSET_OF(struct my_data_struct, a), OFFSET_OF(struct my_data_struct, b), OFFSET_OF(struct my_data_struct, c), OFFSET_OF(struct my_data_struct, d), OFFSET_OF(struct my_data_struct, e), };
You can get a good explanation of all this stuff here