0

On a project I need to get the offset of particular structure members. However I can't use any macros. So I tried to take the logic behind this

#define OFFSETOF(struct_name, fld_name) \
    (unsigned int)&(((struct_name *)0)->fld_name)

And to transform it into a function which gives me this.

unsigned long offset_of_1(void *ptr, void *field)
{
    return ((unsigned long)field - (unsigned long)ptr);
}

It works as long as I use a structure that has been initialized, it is the only work around I found that seems to be working. But I was wondering if there was a better way of doing this ?

  • 1
    No way. It would require passing a **type** as an argument. This kind of tricks are only available in dynamically typed languages. – tstanisl Feb 14 '23 at 11:24
  • 2
    `unsigned long` is potentially problematic on 64-bit architecture, appropriate type to use would be `uintptr_t` to cast the pointers into – once calculated the difference you still can return unsigned long. – Aconcagua Feb 14 '23 at 11:26
  • If one has `&parent` and `&parent.member` then one can do `(char*)&parent.member - (char*)&parent`. However, there are some very obscure subtleties that makes this calculation a technical *undefined behavior*. – tstanisl Feb 14 '23 at 11:26
  • 1
    note that `offsetof` is a part of standard library. This macro is available in `stddef.h`. There is no need to write it yourself. – tstanisl Feb 14 '23 at 11:29
  • 3
    "*can't use any macros*" - I mean, even from standard headers? `offsetof` is a standard macro that comes with any conforming standard library implementation. It even typically expands nowadays to a compiler intrinsic that doesn't put you in UB-land. What about using the compiler intrinsic directly than? – StoryTeller - Unslander Monica Feb 14 '23 at 11:30
  • @tstanisl This other calculation shouldn't be undefined behaviour as long as parent and member point into the *same* object (or at least two objects in the same array...): *Any* type can legally be cast to `char*` without strict aliasing issues, and with above condition held the two pointers point into an object resulting from one single allocation. – Aconcagua Feb 14 '23 at 11:31
  • 4
    You need to work to get your project's requirements changed. Instead of "no macros" you need to say "no user-defined macros" or "no macros not defined by the implementation" or "no macros not defined by the C Language Standard". If you tried to disallow all macros, that would mean you typically couldn't use `NULL`, `FILE *`, `errno`, or anything in ``, either. – Steve Summit Feb 14 '23 at 11:38
  • @Aconcagua, the problem is very technical. Basically `(char*)&parent.member` is **not the same** as `(char*)&parent + offsetof(struct parent, member)`. The l-value `parent.member` is allowed to "lose" information that it is a part of a larger object. This results in pointer arithmetic between pointers from two distinct arrays. This introduces issues when using `container_of` pattern. Please read great [post](https://stackoverflow.com/a/70417758/4989451) about this issue. – tstanisl Feb 14 '23 at 11:41
  • 4
    @Aconcagua It's only undefined if you or I do it. It's not undefined if the implementation does it. :-) – Steve Summit Feb 14 '23 at 11:41
  • @SteveSummit Indeed, but this macro *seems* to be user-defined... – Aconcagua Feb 14 '23 at 11:47
  • 1
    @Aconcagua "*The original macro actually yields undefined behaviour for dereferencing a null pointer...*". The undefinedness would come from the pointer arithmetic; there is no deferencing for the same reason that `&*foo` has no dereferencing. Although not explicitly stated in the standard in the case of `&` and `->`, it is explicitly stated for `&` and `*`, and for `&` and `[]`. (This undefinedness does not apply to the `offsetof()` macro defined in ``, even if it uses the same trick.) – Ian Abbott Feb 14 '23 at 11:57

1 Answers1

0

if there was a better way of doing this ?

Use the standard library offsetof().

Either

  1. "I can't use any macros." --> Approach the rule makers to allow standard library macros. @StoryTeller - Unslander Monica @Steve Summit

  2. Post the code that appears to "need to get the offset of particular structure members" and perhaps an alternative is possible.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256