【问题标题】:casting void pointer in the same variable leads to compilation error在同一个变量中强制转换 void 指针会导致编译错误
【发布时间】:2017-09-05 23:52:31
【问题描述】:

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

【问题讨论】:

  • 您不能取消引用(即应用运算符 * 或运算符 -&gt; 到)空指针。
  • 你认为check = ((test *) check);改变了checktype吗?
  • @MooingDuck 为什么不改变支票的类型?
  • 因为对象的类型是由它的声明决定的,而不是由以后可能分配给它的任何值决定的。这:check = ((test *) check);check 的值从void* 显式转换为test*,然后通过赋值隐式地将结果转换回void*。同样,int n; n = 2.5; 不会导致n 能够保存小数值;它仍然是int
  • check = ((test *) check); 什么都不做。你的编译器可能会优化它

标签: c pointers


【解决方案1】:

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

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

在第二行,我们告诉编译器 “我知道我将 ptr 声明为 (void *),但我比你聪明,相信我,它实际上是 (test *)”。什么都没有改变,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");

这是因为,在底层,编译器将结构中的命名变量视为结构所在位置的偏移。

// 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;

如果我们告诉编译器它是 a (testAB *),那么 'a' 表示第一个 int,而 'b' 表示第二个。如果我们告诉编译器它是a (testBA *),那么'a'是第二个,'b'是第一个。

在编译后的代码中,ALL 变量名会丢失。编译器将结构分配减少到“将结构的第二个 int 设置为 2”。或者更具体地说,如果我们正在处理 32 位整数,则将结构的字节 5、6、7 和 8 设置为 0000、0000 0000 0010(二进制。(或者如果我们正在编译一点,也可能是相反的顺序) CPU 字节序)

【讨论】:

    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 2021-10-26
    • 2012-11-02
    • 2012-11-17
    相关资源
    最近更新 更多