2015-10-14 133 views
12

下面两个铸件有什么区别吗?铸造虚空指针

int a=10; 
int *p=&a; 

(void)p;   //does not give any warning or error 

(void *)p;  //error: statement with no effect [-Werror=unused-value] 

gcc -Wall -Werror --std=c99 -pedantic

Just saw that in this answer.遵守(显然我误解的东西)

回答

11

是的,很明显。

(void)p; 

意味着对象得到浇铸到void类型,(这不是一个完整的类型),并且是完整的表达式,该表达式的结果不应该被使用的,因此编译器不检查它的使用。

引用C11标准,章节6.3.2.2,void

一个void表达(即具有类型空隙的表达)的(不存在的)值不应 以任何方式被使用,[... ...]如果任何其他类型的表达式被评估为void 表达式,则其值或指示符将被丢弃。

因此,不会产生警告或错误。

OTOH,

(void *)p; 

表示对象是一个指向void类型,这是一个完整的类型,因此应该在程序中使用。在这种情况下,编译器正确地报告不在表达式中使用对象。

+0

由'p'指向的地址前的铸造值是否有任何变化? – ameyCU

+0

@ameyCU nopes。只有在有副作用的情况下,才会生效,而这种情况并非如此。 –

+0

并且再次将'p'转换为'int *'将会安全吗? – ameyCU

14

当你

(void) p; 

你告诉编译器根本不顾表达p的结果。这实际上是相同的空语句:

; 

当你

(void *) p; 

你告诉编译器把变量p作为一种通用的指针,而这对于充分表达声明,这个表达式并没有真正做任何事情,并且你得到错误信息。

+0

你可以给这个功能一些真实世界的使用吗? –

+1

@DavidHaim:我曾经在某些只在'IFDEF'内部使用某些局部变量的情况下看到了它,以便在使用带有'ELSE'分支的设置进行编译时不会引发警告。 –

+0

大声笑,所以声明ELSE分支内的局部变量,如果它是唯一触及它的地方。或者我想它是从一个时期开始的,你可以在范围的开始处声明所有的变量.. –