遇到一个场景,结构体B中包含有结构体A的匿名成员,需要单独对一个 B* 初始化其中的 A* 部分。

情况1

如果把类型转换后的指针作为函数参数,实际上是将内存地址传递给函数,函数通过这个地址修改内存内容,不需要修改指针变量本身。此时代码是这样的:

typdef struct A{
	int x;
	int y;
} A;
typedef struct B{
	struct A;
	int z;
}

void initA(A* ptr){
	ptr->x = 0;
	ptr->y = 0;
}

int main(int argc, char** argv){
	B* b = (B*)malloc(sizeof(B));
	initA((A*)b);
}

因为传入的参数 (A*)b 修改的是指针类型,而不是指针指向的地址,所以这是安全的,也能部分初始化B中的属于A的部分。

情况2

如果把类型转换后的指针作为赋值左值,也就是会试图修改指针变量本身,这时候代码是这样的:

A* newA(){
	return (A*)malloc(sizeof(A));
}

int main(int argc, char** argv){
	B* b = (B*)malloc(sizeof(B));
	(A*)b = newA();
}

不幸的是,这样的代码是无法按照预期工作的,因为 (A*)b 是一个右值,是一个临时表达式,它的值无法被修改。

总结

本质的区别在于,一个用法是使用指针指向的地址,此时类型转换不会对效果产生印象;一个是修改指针指向的地址本身,这是需要警惕的一种操作,因为可能会导致内存泄漏等问题。