指针整数强制转换的定义

rto*_*ala 5 c c++ language-lawyer

我对从指针到整数和各种相关操作的转换的定义性(未定义性、实现定义性)感兴趣。我主要对 C11 感兴趣,但欢迎其他标准版本(甚至 C++)的答案。

出于这个问题的目的,假设 C 实现提供了intptr_t.

考虑以下函数:

#include <assert.h>
#include <stdint.h>

int x;
int y;
int z[2];

void f1(void) {
    int *p = &x;
    intptr_t i = p;
}

void f2(void) {
    int *p = &x;
    intptr_t i1 = p;
    intptr_t i2 = p;
    assert(i1 == i2);
}

void f3(void) {
    int *p1 = &x;
    int *p2 = &y;
    intptr_t i1 = p1;
    intptr_t i2 = p2;
    assert(i1 != i2);
}

void f4(void) {
    int *p1 = &x;
    intptr_t i1 = p1;
    int *p2 = i1;
    intptr_t i2 = p2;
    assert(i1 == i2);
}

void f5(void) {
    int *p1 = &z[0];
    int *p2 = &z[1];
    intptr_t i1 = p1;
    intptr_t i2 = p2;
    assert(i1 < i2);
}

Run Code Online (Sandbox Code Playgroud)
  • 哪些函数调用未定义(实现定义)的行为?
  • 如果使用void*而不是有什么改变int*吗?任何其他数据类型作为指针的目标怎么样?
  • 如果我使用 from int*tointptr_t和 back 的显式转换有什么变化吗?(因为 GCC 对演员表发出警告而询问。)
  • 哪些asserts 保证永远不会触发?

Art*_*yer 3

这是 C11 标准的规定intptr_t

7.20.1.4 能够保存对象指针的整数类型

以下类型指定一个有符号整数类型,其属性是任何有效的指针 to 都void可以转换为该类型,然后转换回指针 to void,结果将与原始指针进行比较:

intptr_t
Run Code Online (Sandbox Code Playgroud)

与此相同uintptr_t(除了签名 -> 未签名)。

同样来自“6.5.4p3 Cast Operators”:

除 6.5.16.1 的约束允许的情况外,涉及指针的转换应通过显式强制转换来指定。

其中 6.5.16.1 没有提到将指针分配给整数类型,反之亦然(0常量除外)。这意味着您在分配时确实需要强制转换,gcc 仅允许它作为编译器扩展(并且它根本不使用 进行编译-pedantic-errors

至于这些转换中返回的确切值,标准是这样规定的:

6.3.2.3 指针

p5 整数可以转换为任何指针类型。除非前面指定,否则结果是实现定义的,[...]

p6 任何指针类型都可以转换为整数类型。除非前面指定,否则结果是实现定义的。[...]


您拥有的基本保证是:

intptr_t
Run Code Online (Sandbox Code Playgroud)

并且没有必要强制转换为相同的整数。例如,以下情况可能为真:

int x;
(int*) (void*) (intptr_t) (void*) &x == &x;
/* But the void* casts can be implicit */
(int*) (intptr_t) &x == &x;
Run Code Online (Sandbox Code Playgroud)

在必要时添加强制转换,并将断言转换为返回值(因为assert(false)是未定义的行为),您的函数都没有未定义的行为,但是f2,f4f5可以为 false。f3必须为 true,因为两个整数必须不同才能转换为不同的指针。