void *指针和某些结构的指针(布局)是否兼容?

use*_*672 3 c c++

换句话说,我可以将void*指针重新解释(而不是转换!)作为某种结构类型的void*指针(假设该指针确实包含正确转换的有效结构地址)

实际上,在以下情况下我很有趣:

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?
Run Code Online (Sandbox Code Playgroud)

我在C11标准中发现的情况1相当令人失望:

§6.2.5

28指向void的指针应具有与>指向字符类型的指针相同的表示和对齐要求。相似地,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针应具有相同的表示和对齐要求。所有指向联合类型的指针应具有相同的表示和对齐要求。指向其他类型的指针不必具有相同的表示或对齐要求。

不过,情况2似乎有效,但我不确定100%...

这个问题主要是面向C的,但是我对C ++也很感兴趣(我希望代码在由C ++编译器编译时将是有效的)。老实说,我在C ++ 11标准中发现的更少,所以即使情况2对我来说也值得怀疑...但是,可能是我遗漏了一些东西。

[编辑]这个问题背后的真正问题是什么?

我有一组(可能很大)定义为结构的类型。对于每种类型,我需要定义一个伴随类型:

typedef struct companion_for_sometype
{
  sometype* p_object;
  // there are also other members
}companion_for_sometype;
Run Code Online (Sandbox Code Playgroud)

显然,伴随类型将是C ++中的模板,但是我需要C的解决方案(更确切地说,是“干净的C”,即C89和C ++的交集,因为我希望我的代码也是有效的C ++代码)。

幸运的是,即使在C语言中也不是问题,因为我可以定义一个宏

DECLARE_COMPANION(type_name) typedef struct companion_for_##type_name
{
  type_name* p_object;
  // there are also other members
}companion_for_##type_name;
Run Code Online (Sandbox Code Playgroud)

并针对需要伴随的每种类型调用它。

在伴随类型上也有一组通用操作。这些操作也由宏定义(因为纯C中没有重载)。

例如,其中一项操作

#define op(companion_type_object) blablabla
Run Code Online (Sandbox Code Playgroud)

应该为同伴对象的字段分配一个void*指针p_object,即应该执行以下操作:

(companion_type_object).p_object= (type_name*) some_function_returning_pvoid(..)
Run Code Online (Sandbox Code Playgroud)

但是宏不知道type_name(仅将同伴类型的对象传递给宏),因此宏无法执行适当的指针转换。

这个问题实际上是受这个问题启发的。

为了解决这个问题,我决定将分配中的目标指针重新解释为void *,然后分配给它。可以通过用指针的并集替换伴随声明中的指针来完成(问题在于这种情况),或者可以直接重新解释目标指针,例如:

*(void**) &(companion_type_object).p_object= some_function_returning_pvoid(..)
Run Code Online (Sandbox Code Playgroud)

但是如果不重新解释指针,我将找不到任何解决方案(尽管我可能错过了一些可能性)

oua*_*uah 5

void *是一个可以保存任何对象指针类型的指针,其中包括所有指向结构类型的指针。因此,您可以将指向结构类型的任何指针分配给void *

但是,void *并不能保证指向结构类型的指针具有相同的表示形式,因此情况1是未定义的行为。

(C11,6.2.5p28)“指向其他类型的指针不必具有相同的表示或对齐要求。”