Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are void* pointer and pointer to some structure (layout-) compatible?

Tags:

c++

c

In other words, may I reinterpret (not convert!) void* pointer as a pointer to some structure type (assuming that the void* pointer really holds properly converted valid structure address)

Actually I'm interesting in the following scenario:

typedef struct void_struct void_struct_t;

typedef somestruct
{ 
    int member;
    // ... other members ...
}somestruct_t;

union 
{
    void*          pv; 
    void_struct_t* pvs; 
    somestruct_t*  ps; 
}u;

somestruct_t s={};

u.pv= &s;

u.ps->member=1; // (Case 1)  Ok? unspecified? UB? 

u.pvs=(void_struct_t*)&s;

u.ps->member=1;  // (Case 2) )Ok?

What I found in the C11 standard is rather dissapointing for the Case 1:

§6.2.5

28 A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.[footnote: The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.] Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

It seems, though, that Case 2 is valid, but I'm not 100% sure...

The question is mostly C-oriented, but I'm interesting in C++ too (I'd want the code would be valid while compiling by C++ compiler). Honestly, I found even less in C++11 standard, so even Case 2 seems questionable for me... however, may be I'm missing something.

[edit] What is the real problem behind this question?

I have a (potentially large) set of types defined as structs. For each type I need to define a companion type:

typedef struct companion_for_sometype
{
  sometype* p_object;
  // there are also other members
}companion_for_sometype;

Obviously, the companion type would be a template in C++, but I need a solution for C (more exactly, for "clean C", i.e for intersection of C89 and C++ as I want my code to be also valid C++ code).

Fortunately, it is not a problem even in C, since I can define a macro

DECLARE_COMPANION(type_name) typedef struct companion_for_##type_name
{
  type_name* p_object;
  // there are also other members
}companion_for_##type_name;

and just invoke it for every type that need a companion.

There is also a set of generic operations on companion types. These operations are also defined by macros (since there are no overloads in pure C).

One of this operations, say

#define op(companion_type_object) blablabla

should assign a void* pointer to p_object field of the companion object, i.e. should do something like this:

(companion_type_object).p_object= (type_name*) some_function_returning_pvoid(..)

But the macro doesn't know type_name (only an object of companion type is passed to the macro) so the macro can't do the appropriate pointer cast.

The question is actually inspired by this problem.

To solve it, I decide to reinterpret target pointer in the assignment as void* and then assign to it. It may be done by replacing the pointer in the companion declaration with a union of pointers (the question is about this case), or one may reinterpret target pointer directly, say:

*(void**) &(companion_type_object).p_object= some_function_returning_pvoid(..)

But I can't find any solution without reinterpreting pointers (maybe I'm missing some possibilities though)

like image 586
user396672 Avatar asked Feb 19 '23 18:02

user396672


1 Answers

void * is a pointer that can hold any object pointer type, that includes all pointers to structure type. So you can assign any pointer to a structure type to a void *.

But void * and pointers to structure types are not guaranteed to have the same representation so your case 1 is undefined behavior.

(C11, 6.2.5p28) "[...] Pointers to other types need not have the same representation or alignment requirements."

like image 182
ouah Avatar answered Mar 01 '23 22:03

ouah