铸造一个指针只是躺在你的编译器
void * ptr = malloc(sizeof(test));
((test *)ptr)->a = 5;
在第二行中,我们告诉编译器“我知道我宣布PTR为(void *的),但我比你聪明,相信我,它实际上是一个(测试*)“。没有什么改变,ptr仍然只是一个指针,一个内存位置的地址,但编译器假定它指向某个特定的东西。
check->a = 2; //this raises an error (dereferencing void pointer) when compiling
您必须投你想要的编译器把它看作你从什么宣称它是不同的,每一次的变量。
一个更有趣的场景来解释你可以用铸造指针做什么...
// struct with two ints, a and b
typedew struct testAB {
int a;
int b;
} testAB;
// struct with two ints, named in reverse order
typedef struct testBA {
int b;
int a;
} testBA;
int main(void) {
// construct a testAB struct
void *ptr = malloc(sizeof(testAB));
((testAB *)ptr)->a = 0
((testAB *)ptr)->b = 1
// treat ptr as a testBA struct
if (((testBA *)ptr)->a == 1) {
printf("this shouldn't happen, 'a' was set to 0");
}
}
,如果你运行上面的代码,你会发现,printf语句将被执行。尽管我们将'a'设置为0,if语句检查a == 1.
这是因为结构非常简单。在上面的例子中,struct(s)只是两个int,紧挨着彼此。就像两个整数数组,像这样:
int array[2] = {0, 1};
void *ptr = &array;
即使有这样的表示,我们可以骗编译器,我们可以强制编译器把这个“阵”作为我们的结构之一。
if (((testAB *)array)->a == 0)
printf("a is 0");
这是因为,在引擎盖下,编译器将在一个struct命名变量刚刚从何处结构是offests。
// the following two lines have the same affect
((testAB *)array)->a = 0;
array[0] = 0;
// the following two lines have the same affect
((testAB *)array)->b = 2;
array[1] = 2;
如果我们告诉,这是一个(testAB *)编译器,那么 'A' 是指第一个int和 'B' 是指第二。如果我们告诉编译器它是(testBA *),那么'a'是第二个,'b'是第一个。
编译代码ALL变量名称丢失。编译器将结构分配减少到“将结构的第二个int设置为2”。或者更具体地说,如果我们正在处理32位整数,则将结构的字节5,6,7和8设置为0000 0000 0000 0010(二进制)(或者按相反的顺序,如果我们编译一点endian CPU)
你不能解除引用(即将运算符'*'或运算符' - >'应用于)void指针 –
你是否认为'check =((test *)check);'检查'? –
@MooingDuck为什么这不会改变检查的类型? – Kumar