More music: Just an old-fashioned C question…

Dear Dr. GUI:

Here's an old-fashioned C question: How can I obtain the offset of a structure member—as a constant? I need the offset as a constant so that it can be used in an initializer of some other static variable.

Sample code that doesn't work:

struct xStru { int m1; int m2; int m3 };

struct xStru S, *pS;

int m2offset = (char *)&S.m2 - (char *)&S,

m3offset = (char *)&pS->m3 - (char *)pS;

With Microsoft C version 8.00, both the third and fourth lines generate the compiler error message "..2099 initializer is not a constant".

If automatic storage class variables are initialized as above, the compiler generates dumb code such as the following:

mov ax,OFFSET _S+2

sub ax,OFFSET _S

..giving result m2offset

mov ax,OFFSET 4

mov cx,WORD PTR _pS

add cx,ax

sub cx,WORD PTR _pS

..giving result m3offset

(In fairness, this second fragment is optimized-away with /Ox.)

In desperation, I have tried declarations with __based and const attributes, but all to no avail. How can I get the compiler to reveal the offsets that it clearly "knows"?

Thanks,

Jim Sack

Dr. GUI replies:

This is kind of an addressing question, which is kinda like mail. But out of the goodness of his GUI little heart, Dr. GUI will take it for you.

As it turns out, there's a good old-fashioned solution to the problem. If you want the offset of a member of a structure, use the offsetof macro (defined in stddef.h.). Here's an example:

#include <stddef.h>

#include <stdio.h>

struct S

{

int i;

char c;

float f;

double d;

char c2;

short s;

};

 

// Note that extern definitions must be const.

int i = offsetof(struct S,i),

j = offsetof(struct S,c),

k = offsetof(struct S,f),

l = offsetof(struct S,d),

m = offsetof(struct S,c2),

n = offsetof(struct S,s);

 

void main()

{

printf("%d %d %d %d %d %d\n",i,j,k,l,m,n );

}

Note that the offsets are not always what you'd get if you added up the sizes of the members, since the compiler pads structures to avoid accessing data that is longer than a byte across 32-bit boundaries (which is inefficient on Intel and horrendously inefficient on most RISC machines). You may want to lay out structures so as to minimize the amount of padding—for instance, putting the two "char"s and the "short" together would result in no padding at all.