【发布时间】:2012-07-23 17:40:30
【问题描述】:
换句话说,我可以重新解释(不是转换!)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?
我在 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;
显然,伴生类型将是 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;
只需为需要伴侣的每种类型调用它。
还有一组对伴随类型的通用操作。 这些操作也由宏定义(因为在纯 C 中没有重载)。
其中一个操作,比如说
#define op(companion_type_object) blablabla
应该将void* 指针分配给伴随对象的p_object 字段,
即应该做这样的事情:
(companion_type_object).p_object= (type_name*) some_function_returning_pvoid(..)
但是宏不知道 type_name(只有一个伴生类型的 object 被传递给宏) 所以宏不能做适当的指针转换。
这个问题其实是受这个问题启发的。
为了解决这个问题,我决定将赋值中的目标指针重新解释为 void*,然后赋值给它。 可以通过用指针联合替换伴随声明中的指针来完成 (问题是关于这种情况),或者可以直接重新解释目标指针,例如:
*(void**) &(companion_type_object).p_object= some_function_returning_pvoid(..)
但如果不重新解释指针,我找不到任何解决方案(虽然我可能错过了一些可能性)
【问题讨论】:
-
即使它在技术上是 UB,但实际上情况 1 很可能适用于任何编译器/系统,除非结构是多态的/使用继承。
-
@smerlin:我怀疑即使是指向多态结构的指针,它也很可能适用于大多数编译器,但是..
-
是的,在大多数情况下,但它肯定不适用于使用虚拟多重继承的类/结构。
-
@user396672 - 你想做什么?也许我们可以回答如何做到这一点?
-
C 和 C++ 在这些方面确实存在差异,因此您的 C++ 标签可能具有误导性。