请考虑以下示例程序:
#include <stdio.h>
struct base {
int a, b;
};
struct embedded {
struct base base;
int c, d;
};
struct pointed {
struct base* base;
int c, d;
};
static void base_print(struct base* x) {
printf("a: %d, b: %d\n", x->a, x->b);
}
static void tobase_embedded(void* object) {
base_print(object); // no cast needed, suitably converted into first member.
}
static void tobase_pointed(void* object) {
struct base* x = *(struct base**) object; // need this cast?
base_print(x);
}
int main(void) {
struct embedded em = {{4, 2}};
struct pointed pt = {&em.base};
tobase_embedded(&em);
tobase_pointed(&pt);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译:
$ gcc -std=c99 -O2 -Wall -Werror -pedantic -o main main.c
Run Code Online (Sandbox Code Playgroud)
预期的产出是:
$ ./main
a: 4, b: 2
a: 4, b: 2
Run Code Online (Sandbox Code Playgroud)
C99标准说明了结构的第一个成员:
C99 6.7.2.1(13):指向适当转换的结构对象的指针指向其初始成员......反之亦然.在结构对象中可能存在未命名的填充,但在其开头不是.
在示例程序中,指针struct embedded转换为指向struct base(通过void*)的指针,而不需要显式转换.
如果相反第一个成员是指向基数的指针struct pointed怎么办?我不确定内部演员tobase_pointed.没有铸造垃圾被打印,但没有编译警告/错误.随着投了正确的值base.a,并base.b进行打印,但是并没有真正意味着什么,如果有不确定的行为.
演员转换struct pointed成第一个成员struct base*是否正确?
该代码不仅进行强制转换,还取消对指向结构基指针的指针的引用。这是首先获得指向基址的指针所必需的。
tobase_pointed如果删除该函数,您的代码中会发生以下情况:
struct pointed pt = {&em.base};
void* object = &pt; //pass to the function
struct base** bs = object; //the cast in the function
assert( bs == (struct base**)&pt ) ; //bs points to the struct pointed
assert( bs == &(pt.base) ) ; //bs also points to the initial member struct base* base
struct base* b = *bs ; //the dereference in the function
base_print(x);
Run Code Online (Sandbox Code Playgroud)
bs是经过适当转换以指向初始成员的指针。你的代码是正确的。