2017-09-05 52 views
-5

我正在测试我在将void指针投射到同一变量中的不同类型时遇到的问题。这个问题似乎是在对铸造的指针使用相同的变量时。下面我有一段代码来测试这个。有人能够告诉我为什么该程序无法编译为这种情况?在相同变量中投射void指针会导致编译错误

#include <stdlib.h> 

typedef struct test { 

    int a; 

}test; 

int main() { 

    void * check; 
    test * check2; 
    check = malloc(sizeof(test)); 

    check = ((test *) check); 
    check2 = (test *)check; 


    check->a = 2; //this raises an error (dereferencing void pointer) when compiling 
    check2->a = 2; //this works 
    ((test *)check)->a = 2; //this also works 
} 
+2

你不能解除引用(即将运算符'*'或运算符' - >'应用于)void指针 –

+2

你是否认为'check =((test *)check);'检查'? –

+0

@MooingDuck为什么这不会改变检查的类型? – Kumar

回答

0

铸造一个指针只是躺在你的编译器

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)