根据 C 标准,允许将指向结构的指针强制转换为该结构的第一个成员类型的指针。 但是,是否可以反其道而行之呢?
考虑以下示例:
//texture.h
typedef struct HAL_TEXTURE {
size_t w;
size_t h;
} HAL_TEXTURE;
HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data);
void BindTexture(HAL_TEXTURE* texture);
// d3d10/texture.c linked on windows
typedef struct D3D10_TEXTURE { // not visible outside of this translation unit
HAL_TEXTURE agnostic;
ID3D10ShaderResourceView* srv;
} D3D10_TEXTURE;
HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data) {
D3D10_TEXTURE* texture = calloc(...);
//...//
return (HAL_TEXTURE*)texture; // ok, according to standard
}
void BindTexture(HAL_TEXTURE* texture) {
D3D10_TEXTURE* tex = (D3D10_TEXTURE*)texture; // is this allowed?
//...//
//access D3D10 specific stuff here
}
// ogl/texture.c linked on linux
typedef struct OGL_TEXTURE { // not visible outside of TU
HAL_TEXTURE agnostic;
GLint id;
} OGL_TEXTURE;
HAL_TEXTURE* CreateTexture(size_t w, size_t h, void* data) {
OGL_TEXTURE* texture = calloc(...);
//...//
return (HAL_TEXTURE*)texture;
}
void BindTexture(HAL_TEXTURE* texture) {
OGL_TEXTURE* tex = (OGL_TEXTURE*)texture;
//...//
//access OpenGL specific stuff here
}
我可以安全地将
HAL_TEXTURE*
(这是 D3D10_TEXTURE
和 OGL_TEXTURE
的第一个成员)转换为封闭类型的指针吗?
编辑:重新阅读其他部分,在我看来这是不允许的。根据ISO C标准(https://www.open-std.org/jtc1/sc22/wg14/www/docs/ n2347.pdf),§6.7.2.1 第 15 段:
- 在结构体对象中,非位域成员和位域所在的单元具有 按声明顺序递增的地址。指向结构体对象的指针, 经过适当转换,指向其初始成员(或者如果该成员是位字段,则指向中的单位 它所在的位置),反之亦然。结构对象内可能存在未命名的填充,但不存在 在它的开始。
虽然§6.5第7段似乎禁止访问存储对象的成员:
对象的存储值只能由具有以下之一的左值表达式访问 以下类型:
— 与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
— 与对象的有效类型相对应的有符号或无符号类型,
— 与有效的限定版本相对应的有符号或无符号类型的类型 对象的类型,
— 聚合或联合类型,其成员中包含上述类型之一 (递归地包括子聚合或包含联合的成员),或
— 字符类型。