据我所知,在 C 语言中,如果将指针转换为整数,则无法保证指针运算的行为反映整数运算的行为。换句话说,无法保证以下任何断言都成立:
char a[2]; // So that p + 1 is a valid memory location
char *p = a;
assert(p + 1 == (char *)((uintptr_t)p + 1));
int x;
int *p = &x;
assert((intptr_t)p % sizeof(int) == 0);
在大多数系统中,这些都会成立。指针的整数表示的尾部位将表示指针对齐,并且向指针添加某个偏移量与将偏移量乘以指针类型的大小添加到指针的整数表示中相同。
但是,有没有办法确定,最好是在编译时,在任何特定的实现中,这些假设是否对任何指针都始终成立,只要指针算法无论如何都会产生一个有效的指针,因为标准不保证它们?例如,在早期不支持的实现上失败,回退到替代实现等。
根据评论中的讨论,问题是 C 标准的规范是否提供了一种可靠的方法来确定断言在任何特定的 C 实现中是否成立。 (因此,问题不在于 C 实现是否可以提供某种方法来了解这一点,例如通过预定义程序可以测试的预处理器宏。问题是是否存在适用于所有 C 实现的测试。)
答案是否定的。
由于这个答案依赖于 C 标准中没有关于此内容的事实,因此除了引用整个 C 标准之外,没有其他方法可以证明这一点。我对当前的 C 标准相当熟悉,并且相信它没有提供任何此类机制。
C 2018 6.3.2.2 5 的注释 69 告诉我们“将指针转换为整数或将整数转换为指针的映射函数旨在与执行环境的寻址结构保持一致”,但这不是标准的规范部分,我认为标准中没有任何内容表明 C 实现应提供有关此映射的任何信息。也没有声明任何指针和整数映射的属性来提供断言是否始终成立的测试。
您实际上无法在整数常量表达式中执行指针运算。因此,我认为正确编译测试此问题的唯一方法是创建另一个程序并输出一个可以执行的预处理器常量
#if
。但是,这可能不是必需的。事实上的编译时表达式可能可以做到。在 gcc 和 clang 上,测试如下:
已优化(不在带有
char *p = a;
赋值的 clang 上),即,测试 if 被视为事实上的编译时常量(https://godbolt.org/z/z85a9W3E8)。依赖此优化可能对您来说就足够了。要测试任何指针,您应该测试允许具有不同表示的指针类型。本机指针类型可以。结构/联合指针可能不行。或者也许不要测试并声明不适用的平台不值得支持。