Replacement for offsetof

F

Fred Zwarts

Consider the following definition:

typedef struct {
int a;
int b[100];
} s;

Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.

I used to use the offsetof macro for this purpose:

offsetof (s, b)

For most compiler environments offsetof is defined as a macro as follows
in stddef.h:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

and in these cases my function works as I expected..

However, I now have a new compiler which uses a built-in function instead of this macro.
A error message is generated at compile time for my use of offsetof because
this built-in function requires that the second parameter of offsetof is a
compile-time constant. (I understand that there is some discussion about
the exact wording and interpretation of the standard with respect to the
constant requirement for offsetof.)

I have two questions, a theoretical and a practical one.

Why does the standard impose this limitation to offsetof?
It seems that there is a need to compute offsets that are not compile-time constants.

What is the best way to replace offsetof (s, b) in such a way that the result is
defined according to the C++ standard?
I understand that the result of the usual macro is not really defined because
a) address 0 does not necessarily have the value 0 and
b) type casting an address to size_t is not necessary well defined in all environments.

Regards,
Fred.Zwarts.
 
B

Ben Pope

Fred said:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;

In C++, it is preferred to do:
struct s {
int a;
int b[100];
};
Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.


Why?

Ben Pope
 
F

Fred Zwarts

Ben Pope said:
Fred said:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;

In C++, it is preferred to do:
struct s {
int a;
int b[100];
};
Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.


Why?


Because the result must be added to a base address to find the address of a hardware register.

Fred.Zwarts.
 
B

Ben Pope

Fred said:
Ben Pope said:
Fred said:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;
In C++, it is preferred to do:
struct s {
int a;
int b[100];
};
Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.

Why?


Because the result must be added to a base address to find the address of a hardware register.


s var;
reinterpret_cast<int*>(&(var.b)) - reinterpret_cast<int*>(&var)

Assuming int is the word size of your architecture, or at least the size
of your hardware registers.

It's not nice, but obviously portability is not a factor.

Ben Pope
 
A

Andre Kostur

Fred said:
Ben Pope said:
Fred Zwarts wrote:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;
In C++, it is preferred to do:
struct s {
int a;
int b[100];
};

Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.
Why?


Because the result must be added to a base address to find the
address of a hardware register.


s var;
reinterpret_cast<int*>(&(var.b)) - reinterpret_cast<int*>(&var)

Assuming int is the word size of your architecture, or at least the
size of your hardware registers.

It's not nice, but obviously portability is not a factor.


Or how about:

offsetof(s, b) + (i * sizeof(b[0]))

Determine the offset of the array b within the struct, then add the index
distance into b.
 
F

Fred Zwarts

Ben Pope said:
Fred said:
Ben Pope said:
Fred Zwarts wrote:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;
In C++, it is preferred to do:
struct s {
int a;
int b[100];
};

Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.
Why?


Because the result must be added to a base address to find the address of a hardware register.


s var;


This allocates a variable from the stack, which could in some cases consume quite some memory.
(The type s is just an example. The real world structs can be much more complex and much larger.
VME memory can be quite large.)
Is there a way to calculate the offset without allocating memory.
reinterpret_cast<int*>(&(var.b)) - reinterpret_cast<int*>(&var)


I wonder whether the address arithmetic is correct.
You subtract two int* addresses.
Shouldn't you subtract two integers?
Probably you meant reinterprete_cast said:
Assuming int is the word size of your architecture, or at least the size
of your hardware registers.

It's not nice, but obviously portability is not a factor.

As a matter of fact, portability is a factor.
The code is used for access to VME devices.
The code is used on different processors with different VME interfaces
(and different compilers).
Probably reinterprete_cast<size_t> instead of reinterprete_cast<int> will
already be more general.

But I wonder what the general solution is
with a well defined behavior according to the C++ standard.

Fred.Zwarts.
 
F

Fred Zwarts

Andre Kostur said:
Fred said:
Fred Zwarts wrote:
Consider the following definition:

typedef struct {
int a;
int b[100];
} s;
In C++, it is preferred to do:
struct s {
int a;
int b[100];
};

Now I have a function

void f (int i) { ... }

which needs to calculate the offset within s of b.
Why?


Because the result must be added to a base address to find the
address of a hardware register.


s var;
reinterpret_cast<int*>(&(var.b)) - reinterpret_cast<int*>(&var)

Assuming int is the word size of your architecture, or at least the
size of your hardware registers.

It's not nice, but obviously portability is not a factor.


Or how about:

offsetof(s, b) + (i * sizeof(b[0]))

Determine the offset of the array b within the struct, then add the index
distance into b.


Thanks, that seems to be a portable solution in this simple case.
But now suppose b is defined as
int b[sizeA][sizeB][SizeC];
Of course I can write out the complete indexing arithmetic to get
the offset of b[j][k].
The nice thing of the old offsetof behavior was that the compiler
did it for me.
I am looking for a macro which can easily replace offsetof.

Fred.Zwarts.
 
B

Ben Pope

Fred said:
This allocates a variable from the stack, which could in some cases consume quite some memory.
(The type s is just an example. The real world structs can be much more complex and much larger.
VME memory can be quite large.)
Is there a way to calculate the offset without allocating memory.

Understood. I assumed you'd do the arithmetic on an already allocated
struct, or overlay a struct over your registers with a placement new
(neither of which would necessarily require an allocation).
reinterpret_cast<int*>(&(var.b)) - reinterpret_cast<int*>(&var)


I wonder whether the address arithmetic is correct.
You subtract two int* addresses.
Shouldn't you subtract two integers?
Probably you meant reinterprete_cast<int>.


Nope. I take advantage of pointer arithmetic. This gives you the
offset in sizeof(int) steps.
As a matter of fact, portability is a factor.

OK, but if it's mapped to registers, I figured it would be platform
specific.
The code is used for access to VME devices.
The code is used on different processors with different VME interfaces
(and different compilers).
Probably reinterprete_cast<size_t> instead of reinterprete_cast<int> will
already be more general.

Why? size_t is just as variable as int, or indeed int*.
But I wonder what the general solution is
with a well defined behavior according to the C++ standard.

The behaviour I describe is well defined. It's just specific to the
architecture, or more specifically, the size of int. It's just as
dependant on the architecture as the struct itself.

Andre Kostur has a solution that will work for you if you don't already
have a struct in existence or is not accessible.

Ben Pope
 

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,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top