14

I want to find the byte offset of a struct member at compile-time. For example:

struct vertex_t
{
    vec3_t position;
    vec3_t normal;
    vec2_t texcoord;
}

I would want to know that the byte offset to normal is (in this case it should be 12.)

I know that I could use offsetof, but that is a run-time function and I'd prefer not to use it.

Is what I'm trying to accomplish even possible?

EDIT: offsetof is compile-time, my bad!

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Colin Basnett
  • 4,052
  • 2
  • 30
  • 49

3 Answers3

9

offsetof is a compile time constant, if we look at the draft C++ standard section C.3 C standard library paragraph 2 says:

The C++ standard library provides 57 standard macros from the C library, as shown in Table 149.

and the table includes offsetof. If we go to the C99 draft standard section 7.17 Common definitions paragraph 3 includes:

offsetof(type, member-designator)

which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes [...]

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
3

In C:

offsetof is usually actually a macro, and due to its definition, it will probably optimized by the compiler so that it reduces to a constant value. And even if it does become an expression, it is small enough that it should cause almost no overhead.

For example, at the file stddef.h, it is defined as:

#define offsetof(st, m) ((size_t)(&((st *)0)->m))

In C++:

Things get a bit more complicated, since it must resolve offsets for members as methods and other variables. So offsetof is defined as a macro to call another method:

#define offsetof(st, m) __builtin_offsetof(st, m)

If you need it only for structs, you are good enough with offsetof. Else, I don't think it is possible.

  • 2
    Those are *sample* definitions. The standard doesn't specify how `offsetof` is defined, just how it behaves. – Keith Thompson Nov 13 '13 at 01:11
  • In C++ `offsetof` is undefined except on a standard-layout struct. "Optimized" to a constant value still wouldn't make it an integral constant expression. – Potatoswatter Nov 13 '13 at 01:22
  • @KeithThompson You are right. I took these definitions from the version of libc I'm using right now. – Vinícius Gobbo A. de Oliveira Nov 13 '13 at 22:28
  • @Potatoswatter You are right. The way I understand it, every modern compiler with the appropriate flags is very likely to reduce the whole expression to a constant value, since it is very likely to become an expression with only constants operands. I should be more clear in my answers. Thank you for your comment! – Vinícius Gobbo A. de Oliveira Nov 13 '13 at 22:31
  • 2
    In C, `offsetof` is *required* to be a macro, and it's required to expand to an integer constant expression. See [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 7.19 paragraph 3. C++ also requires `offsetof` to be a macro (C++12 18.2 [support.types]). C++ adds a paragraph of description on top of what it inherits from C; I don't know C++ well enough to tell whether the C++ rules imply `offsetof` must expand to an integer constant expression. – Keith Thompson Nov 13 '13 at 22:38
1

Are you sure it is run-time?

The following works..

#include <iostream>
#include <algorithm>


struct vertex_t
{
    int32_t position;
    int32_t normal;
    int32_t texcoord;
};

const int i = offsetof(vertex_t, normal); //compile time..

int main()
{
    std::cout<<i;
}

Also see here: offsetof at compile time

Community
  • 1
  • 1
Brandon
  • 22,723
  • 11
  • 93
  • 186
  • 1
    In C++ the initializer of a `const int` doesn't need to be determined at compile time. Try using `offsetof` as an array bound instead. – Potatoswatter Nov 13 '13 at 01:23
  • From: http://stackoverflow.com/questions/436300/are-constant-c-expressions-evaluated-at-compile-time-or-at-runtime `The implementation is free to calculate it at runtime, but it must also be able to calculate it at compile time, because it must give a diagnostic message if a constant expression is not representable in the type that its expression has and if such expressions are allowed in contexts that require the value at translation time, for example if used as the size of an array dimension.` So yes it does need to be determined at compile time. – Brandon Nov 13 '13 at 02:15
  • No, the initializer of a `const` object is not a constant expression. – Potatoswatter Nov 13 '13 at 05:19
  • offsetof expands to a constant expression. Since when is a "primitive type" an object? If it is not a constant expression then it is just a constant value assigned at compile time. – Brandon Nov 13 '13 at 15:26
  • Instances of primitive types in C and C++ are called objects just like instances of class type. C requires resolution at compile time but C++ will perform any runtime task you want. Try `std::ostream &my_os = std::cout << "hello, world\n";`. – Potatoswatter Nov 14 '13 at 01:33
  • Since we now have `constexpr`, you should use that if you want to make sure it's computed at compile time. – Alexis Wilke Mar 05 '23 at 02:52