我不是在寻找其他方法,我想专注于这个特定的问题,看它是否起作用或者为什么不起作用。
(如果我无意中犯了一些无关的错误,请告诉我,我会修复它)
c11标准如下:
6.2.5.28 所有指向结构类型的指针应具有相同的表示和对齐要求。
6.7.2.1.6 结构体是由一系列成员组成的类型,其存储按顺序分配。
这意味着结构体A和B中指针的大小和对齐方式是相同的。
#include <stdio.h>
#include <stdlib.h>
struct S1
{
int i ;
} ;
struct S2
{
float f ;
} ;
struct A
{
struct S1* p ;
} ;
struct B
{
struct S2* p ;
} ;
int main( void )
{
结构体A和B都有指向S1和S2结构体的指针,并且保证结构体A和B具有相同的大小和对齐方式。
我们有一个struct B
,其成员指针是一个指向S2结构体的指针,但它指向某个S1结构体,这是通过void*转换实现的。
struct S1 s1 = { 0 } ;
struct B* b = malloc( sizeof( *b ) ) ;
b->p = ( void* ) &s1 ;
没问题,我们可以存储指针,只要我们不实际使用指针。 但我们想使用它。 我们可以将指针强制转换为struct S1。
( ( struct S1* )(b->p) )->i = 123 ; //redundant brackets for emphasis
printf("%d\n" , s1.i ) ;
并且正确地使用它。
到目前为止,我没有看到任何问题,因为指针被转换为正确的类型。
但是我们可以将整个结构体B转换为结构体A吗?尽管它们在大小和对齐方面相同,但标准可能会抱怨(?), 编译器会产生未定义的行为吗?
( ( struct A* )b)->p->i = 666 ;
printf("%d\n" , s1.i ) ;
我知道解决方法是使用联合体(或使用void并在每次正确转换时进行),因为标准允许使用未使用的成员来存储值。
6.5.2.3.3(95) 如果用于读取联合体对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的适当部分将被重新解释为新类型的对象表示,如6.2.6所述(有时称为“类型字谜”)。 这可能是一个陷阱表示。
但是,我想避免这种情况:
struct C
{
union
{
struct S1* p1 ;
struct S2* p2 ;
} ;
} ;
struct C* c = malloc( sizeof( *c ) ) ;
c->p2 = ( void* )&s1 ;
c->p1->i = 444 ;
printf("%d\n" , s1.i ) ;
return 0 ;
}