A portable way to calculate pointer to the whole structure using pointer to a field declared inside the structure (aka CONTAINING_RECORD macro)

后端 未结 2 1343
青春惊慌失措
青春惊慌失措 2021-01-05 12:56

There is the well known CONTAINING_RECORD() macro defined, for instance, in Winnt.h:

#define CONTAINING_RECORD(address, type, field) ((type *)( \\
                  


        
相关标签:
2条回答
  • 2021-01-05 13:29
    1. No, none of the one's you have given is compliant. Dereferencing a null pointer isn't, typeof isn't and ({ ... }) expressions aren't.

    2. yes, the second part of the linux thing rewritten properly (type *)((char *)(ptr) - offsetof(type, member)) is compliant. (offsetof is defined in the standard)

    3. see 2

    AFAIK, all this is valid for C and C++

    Edit: The linux thing tries to add additional security to the macro by checking if a pointer to the member and the pointer in the argument are assignment compatible. As far as I can see the gcc extension typeof is essential for such an approach in C.

    With C99, you could though use a "compound literal" to have a somewhat weaker check by doing something like

    (type){ .member = *(ptr) }
    

    but this would only tell you if the type of *ptr is assignment compatible to member. E.g if ptr would be float* and member double this would still work.

    In any case, the check of the types only gives you false security. You must be pretty sure that your ptr really comes from inside type to use this. Be careful.

    Edit: As bert-jan remarks in his comments below, in C++, when there is virtual inheritance, the offsetof macro has the fundamental problem that the offset of member cannot be determined at compile time. I am not convinced that the present idea of a container macro then makes any sense in such a context. Be extremely careful.

    0 讨论(0)
  • 2021-01-05 13:38

    Your ways to determine the address of the containing structure work only if 'type' is a type that does not use multiple inherritance. Otherwise, the macros would dereference the NULL pointer, and that is always guaranteed trouble. I once asked a question about this matter ( Is this valid ANSI C++ code? Trying to generate offsets of structure members at compile-time ).

    0 讨论(0)
提交回复
热议问题