问题 为什么(void **)类型可以赋值给(void *)或(int *)?


这是我的C代码:

int main()
{
    void * ptr_void;
    void ** ptr_2void;
    ptr_void = ptr_2void;
    return 0;
}

我只是想知道为什么这段代码有效?我指定了一个 (void *) 至 (void **),编译器甚至在没有警告的情况下传递它。这种类型看起来不匹配。和以下代码分配 (void **) 至 (int *) 也有效。

int main()
{
    int * ptr_int;
    void ** ptr_2void;
    ptr_int = ptr_2void;
    return 0;
}

任何人都能弄明白究竟是什么 (void *) 东东?


7289
2017-12-24 15:28


起源

任何数据指针类型都可以转换为/从 void*。 - Barmar
@Barmar:“演员”?这个问题与任何演员都没有任何关系。问题是关于隐式转换。不,不是任何数据指针类型都可以隐式转换为/从 void *。在这种情况下,仍然会执行简历资格。 - AnT
`我已经将(void *)分配给(void **)`应该是`我已经将(void **)分配给(void *)` - nishantjr


答案:


void指针的类型转换为隐式指向任何其他数据类型的指针。编译器不会显示任何警告。类似地,从任何类型的指针转​​换为 void * 也会在没有警告的情况下工作。

除了void指针之外,如果您尝试隐式地从一种指针类型转换为另一种指针类型,则编译器将发出警告。

例如,考虑下面给出的代码,它会给你警告“assignment from incompatible pointer type”。

  int *intptr;
  void *voidptr;
  void **vvptr;
  int intval=123;
  voidptr=&intval;
  vvptr=voidptr;
  intptr=vvptr; 

导致警告的代码行是 intptr=vvptr; 因为 intptr 是一个 integer pointer 和 vvptr 是一个类型的指针 void **。他们都不是 void * 指针,因此是一个警告。

为了避免这种警告,你必须显式地输入cast void ** 输入到 int * 类型。如果你改变了这条线 intptr=vvptr;  至 intptr=(int *)vvptr; 然后编译器不会显示警告。


11
2017-12-24 15:35



谢谢所有人。完全理解它。 - kevin
我认为你混淆了演员和转换。最后一句话是完全错误的(对于我见过的所有编译器而言)。 - undur_gongor
呃......这看起来很不合逻辑 void * 转换为任何其他类型而没有警告 int * 被转换为 void * 警告。哪种编译器的行为方式?通常在C语言指针中进行转换 void * 在没有任何警告的情况下执行。此外,这个问题与“类型转换”无关。 - AnT
@AndreyT:也许在这里与C ++存在一些混淆? - Keith Thompson
@Keith Thompson:可能,但即使在C ++隐式转换中也是如此 至  void * 被允许并安静地进行。 - AnT


区分a是很重要的 转变 和a

转换将一种类型的值转换为另一种类型的值。强制转换是一个运算符(由括号中的类型名称组成),它明确指定转换。转换可以是显式的(由强制转换运算符指定)或隐式转换。大多数指针转换需要强制转换操作符;指针转换涉及 void* 是例外。

可以将任何指向对象的指针类型(或指向不完整的指针类型)的值转换为 void* 并回到原来的类型;保证结果指针与原始指针的比较等于。

在赋值中(或者在将参数传递给函数时,或者在函数中传递 return 声明),转换或转换 void* 可以隐式地完成,没有强制转换操作符。

在您的第一个代码示例中:

void * ptr_void;
void ** ptr_2void;
ptr_void = ptr_2void;

允许分配,因为a void** 可以转换为 void* 没有演员。没什么特别的 void** 这里;一个指针 什么 可以转换为 void* 没有演员。 (void* 是一种通用指针类型; void** 是  通用指针到指针类型,实际上没有通用指针到指针类型。)

在您的第二个代码示例中:

int * ptr_int;
void ** ptr_2void;
ptr_int = ptr_2void;

作业是  有效;它是 约束违规。之间没有隐式转换 int* 和 void**因为这两种类型都不是 void*。任何符合C的编译器 必须 为作业发出诊断消息。在某些情况下,诊断可能是一个警告,编译器会 大概 生成隐式转换,就好像你已经编写了一个强制转换。在其他情况下,编译器可能需要其他选项才能使其诊断此违规。

请注意,上述内容不适用于函数指针。任何函数指针类型都可以转换(使用强制转换)到任何其他函数指针类型,将函数指针转换为 void* 反之亦然,具有未定义的行为(尽管某些编译器可能支持)。


4
2017-12-25 01:28



带有函数指针的业务可能与你有一个分区内存模型或者过去在DOS时代曾经存在的时髦模型之一有关。指针可能指向非常不同的内存块,即使它们具有相同的位模式(谢谢,英特尔段寄存器!)或它们可能具有不同的宽度。现在,关闭以获得一些蛋酒来帮助我再次忘记这些事情! - Donal Fellows


void** 和 void* 是不同的类型。 int* 和 void** 也是不同的类型。但正如巴马尔所说, any data pointer type can be cast to/from void*. 这意味着你可以施展 int* 至 void*,但你不能施展 int* 至 void**作为 void** 没有同样的特殊财产。

gcc 应该发出警告:

warning: assignment from incompatible pointer type [enabled by default]

     ptr_int = ptr_2void;

看到这个问题: 传递给void **而不是void *会让编译器抱怨类型,为什么?

void *是一种可以隐式转换为任何对象的类型   指针类型。 void **不是 - 所以虽然你可以给一个char *分配一个   void *,你不能用char **和void **做同样的事情。

原因是它们是不兼容的类型:char **指向a   char *,void **指向void *,因此它们的基类型不匹配。


1
2017-12-24 15:33