5

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)

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
user396672
  • 3,106
  • 1
  • 21
  • 31
  • Even though if its technically UB, in practice Case 1 will most likely work on any compiler/system, unless the struct is polymorphic/uses inheritance. – smerlin Jul 25 '12 at 10:09
  • @smerlin: I suspect that even for pointers to polymorphic structs it will most likely work for most compilers, but.. – user396672 Jul 25 '12 at 10:19
  • yeah, for most cases, but it will definitly not work for classes/structs using virtual multiple inheritance. – smerlin Jul 25 '12 at 12:21
  • @user396672 - What are you trying to do? Perhaps we can answer how to do that? – Bo Persson Jul 25 '12 at 14:22
  • C and C++ really differ on these things, so your C++ tag is probably misleading. – Jens Gustedt Jul 25 '12 at 16:39
  • @Bo Persson: I've tried to explane the real problem (sorry if the explanation is too verbose). – user396672 Jul 26 '12 at 08:57
  • @Jens Gustedt: Indeed, I hesitated adding C++ tag, but I'm interesting in C++ case too. Maybe add "clean-C" tag to SO for such cases? – user396672 Jul 26 '12 at 09:02

2 Answers2

7

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."

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Are you consider Case 2 as valid? – user396672 Jul 25 '12 at 10:08
  • What is `struct void_struct` ? You didn't declare the structure type in your example. – ouah Jul 25 '12 at 10:12
  • It is just a replacement for void.. I don't want even define it but it may be defined arbitrary if needed – user396672 Jul 25 '12 at 10:16
  • void_struct_t* is just a work around possible UB with void* pointer. it is actually a placeholder for "pointer to any struct". I hope that its union with pointer to actual struct should work... – user396672 Jul 25 '12 at 10:36
  • Case 2 is really equally undefined, because it writes to one union member and reads from another. The C++ standard says *"In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time."*. You can only read from the member that is currently stored in the union. Most compilers have an extension allowing this, but *the language* does not. – Bo Persson Jul 25 '12 at 14:27
  • @BoPersson, there is no "*the language*" this is tagged C++ and C and they differ on that. C allows type puning through `union`s under most circumstances. In fact the primary use of `union`s in C is type puning. – Jens Gustedt Jul 25 '12 at 16:38
2

In C, void * automatically casts to any object type, so this will work:

(companion_type_object).p_object = some_function_returning_pvoid(..)

In C++, you need to use static_cast, but you can find out the required type using decltype :

(companion_type_object).p_object = 
    static_cast<decltype(*(companion_type_object).p_object) *>(
        some_function_returning_pvoid(..))

In C++03 you should be able to use some compiler extension equivalent to decltype. Alternatively, you could provide a macro-generated method on companion_type_object to cast a void * to the appropriate type:

static type_name *void_p_to_object_p(void *p) { return static_cast<type_name *>(p); }
...
(companion_type_object).p_object = companion_type_object.void_p_to_object_p(
    some_function_returning_pvoid(..))
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • but C generates a warning while casting from void* (?) – user396672 Jul 26 '12 at 09:05
  • It shouldn't; are you sure that `some_function_returning_pvoid` actually returns `void *`? – ecatmur Jul 26 '12 at 09:08
  • Thank you, now I understand what I really should do. I need a special macro, say, null_ptr_assign(type_p,void_p) and implement this macro for C++ and C in different manner (and, maybe differently for some C compilers that have decltype analog) – user396672 Jul 26 '12 at 09:22
  • ... and null_ptr_assign(type_p,void_p) may be function template (not a macro) for C++ case (without decltype, so valid even for C++03). I regret I can't choose two answers as accepted (ouah's answer better matches the original question). I can only upvote, though your answer is what I really need. – user396672 Jul 26 '12 at 10:15
  • @user396672 - Do not use void in the first place. The word void is a hint - void aka lack of space or volume. – Ed Heal May 03 '13 at 01:57