c - 将 void * 值设置为 intptr_t 变量是否需要显式转换?

标签 c pointers gcc c99 gcc-warning

我似乎无法理解当我尝试将 void * 值分配给 intptr_t 变量时收到的 GCC 编译器警告。具体来说,当我使用 -std=c99 -pedantic 进行编译时,我收到以下有关第 7 行变量 z 初始化的警告:

warning: initialization makes integer from pointer without a cast [-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 部分:

The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

intptr_t

我是否误解了标准,或者在这种情况下,GCC 在“来自指针的整数”检查中过于迂腐?

最佳答案

总结一下!对于任何错误,请提前致歉 - 请给我留言。

在 C99 中:

  • 任何指针都可以转换为整数类型。1
  • 您可能想要这样做,例如 if you are implementing your own operating system!
  • 指针和整数之间的转换可能会出现严重错误,1因此通常不是您想要的。
  • 因此,当您将指针转换为整数而不进行强制转换时,编译器会发出警告。这并不是过于迂腐,而是为了让您避免未定义的行为。
  • intptr_t(和 uintptr_t,同样贯穿全文)只是一个整数类型,2,因此它面临与任何其他类型相同的风险其他指针到整数的转换。因此,您会收到相同的警告。
  • 但是,使用intptr_t,您至少知道指针的转换不会截断任何位。因此,如果您确实需要指针的整数值,则可以使用这些类型(带有显式强制转换)。

    • 规范1, #6 是这么说的

      ... the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined.

      使用intptr_t,结果可以以整数类型表示。因此,该行为不是未定义,而只是实现定义。这就是(据我所知)为什么这些类型可以安全地用于从指针接收值。

编辑

下面的引用文献 1 是第 6.3 节“转换”的一部分。规范说:3

Several operators convert operand values from one type to another automatically. This subclause specifies the result required from such an implicit conversion...

并引用第 6.5.4 节对显式强制转换的讨论。因此,引用文献 1 中的讨论确实涵盖了从任何指针类型到 intptr_t 的隐式转换。根据我的阅读,从 void *intptr_t 的隐式转换是合法的,并且具有实现定义的结果。1, 4

关于是否应该使用显式强制转换,gcc -pedantic 认为应该使用,而且一定有一个充分的理由! :) 我个人同意显式类型转换更清晰。我也认为如果可能的话,代码应该在没有警告的情况下编译,所以如果这是我的代码,我会添加显式强制转换。

引用文献

1 C99 draft (因为我没有最终规范的副本),秒。 6.3.2.3 #5 和 #6)。

2Id.,秒。 7.18.1.4

3Id.,秒。 6.3

4Id.,秒。 3.4.1,将“实现定义的行为”定义为“每个实现都记录了如何做出选择的未指定行为”。这意味着转换是合法的,但结果在一个平台上可能与另一个平台上不同。

关于c - 将 void * 值设置为 intptr_t 变量是否需要显式转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40029292/

相关文章:

c - 从 xmlNode 获取源文件名?

c - 为什么 `*(multi + row)` 生成指针地址而不是值?

c - "multidimensional array pointer +1"的值不匹配

c - 初始化指向动态内存的全局指针时出错

c - 如何阻止 GCC 在 snprintf() 调用中提示 "directive output may be truncated"?

c - 没有操作系统的嵌入式系统中的 malloc

c - 谁响应内存管理用malloc()

c - GCC 链接器问题与 -lm 标志

c - 数组和指针的异同通过一个实际例子

gcc - C - 如何使用 GCC SSE 向量扩展访问向量元素