在同一个变量中转换void指针会导致编译错误

时间:2017-09-05 23:52:32

标签: c pointers

我正在测试我在将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
}

1 个答案:

答案 0 :(得分:0)

投射指针只是骗你的编译器

void * ptr = malloc(sizeof(test));
((test *)ptr)->a = 5;

在第二行,我们告诉编译器&#34;我知道我宣布ptr为(void *),但我比你聪明,相信我,它&#39;实际上是(测试*)&#34; 。没有任何改变,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语句。即使我们设置了一个&#39;为0,if语句检查a == 1。

这是因为结构非常简单。在上面的例子中,struct(s)只是两个紧密相邻的int。就像一个两个整数的数组,像这样:

int array[2] = {0, 1};
void *ptr = &array; 

即使有了这种表示,我们也可以欺骗编译器,我们可以强制编译器对待这个数组&#39;作为我们的结构之一。

if ( ((testAB *)array)->a == 0 )
  printf("a is 0");

这是因为,在引擎盖下,编译器将结构中的命名变量视为结构所在的结果。

// 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 *),那么&#39; a&#39;意思是第一个int,&#39; b&#39;意味着第二个。如果我们告诉编译器它是(testBA *),那么&#39; a&#39;是第二个,&#39; b&#39;是第一个。

在已编译的代码中所有变量名称都将丢失。编译器减少了struct赋值,直到&#34;将struct的第二个int设置为2&#34;。或者更具体地说,如果我们处理32位整数,则将结构的字节5,6,7和8设置为0000,0000 0000 0010(二进制。(或者如果我们正在编译一点,则可能以相反的顺序) endian CPU)