当我尝试将void *
值分配给intptr_t
变量时,我似乎无法理解GCC编译器警告。具体来说,当我使用-std=c99 -pedantic
进行编译时,我收到有关第7行变量z
初始化的以下警告:
警告:初始化从指针生成整数而没有强制转换[-Wint-conversion]
以下是源代码:
#include <stdint.h>
int main(void){
unsigned int x = 42;
void *y = &x;
intptr_t z = y; /* warning: initialization makes integer from pointer without a cast [-Wint-conversion] */
return 0;
}
当然,如果我明确地将y
强制转换为intptr_t
,那么警告就会消失。但是,当intptr_t
的整个目的是转换和操纵void *
值时,我混淆了为什么隐式转换会出现警告。
来自C99标准的 7.18.1.4 部分:
以下类型指定带有任何有效属性的有符号整数类型 指向 void 的指针可以转换为此类型,然后转换回指向 void 的指针, 并且结果将与原始指针进行比较:
使用intptr_t
我是否误解了标准,或者GCC在指针&#34;&#34; 整数中过于迂腐?检查这种情况?
答案 0 :(得分:3)
在C99:
intptr_t
(和uintptr_t
,同样在整个过程中)只是一个整数类型, 2 因此它与任何其他指针到整数的风险相同转换。因此,您会得到相同的警告。 然而,intptr_t
,您至少知道指针的转换不会截断任何位。所以这些是要使用的类型 - 使用显式强制转换 - 如果确实需要指针的整数值。
规范 1,#6 表示
...... 结果是实现定义的。如果结果无法以整数类型表示, 行为未定义。
使用intptr_t
,结果可以以整数类型表示。因此,行为不是 undefined ,而只是实现定义的。那是(据我所知)为什么这些类型可以安全地用于从指针接收值。
修改强>
下面的参考文献1是第6.3节“转换”的一部分。规范说: 3
多个运算符自动将操作数值从一种类型转换为另一种类型。这个 子条款指定了这种隐式转换所需的结果......
并参考6.5.4节讨论显式演员表。因此,参考文献1中的讨论确实涵盖了从intptr_t
的任何指针类型的隐式转换。通过我的阅读,从void *
到intptr_t
的隐式演员是合法的,并且具有实现定义的结果。 1,4
关于是否应该使用显式强制转换,gcc -pedantic
认为应该,并且必须有充分的理由! :)我个人认为明确的演员阵容更清楚。如果可能的话,我也认为代码应该在没有警告的情况下进行编译,所以如果它是我的代码,我会添加显式转换。
<强>参考强>
1 C99 draft(因为我没有最终规范的副本),秒。 6.3.2.3#5和#6)。
2 Id。,sec。 7.18.1.4
3 Id。,sec。 6.3
4 Id。,sec。 3.4.1,将“实现定义的行为”定义为“未指定的行为,其中每个实现记录了如何做出选择”。这意味着转换是合法的,但结果在一个平台上可能与另一个平台上的结果不同。