是否可以在 C 中比较指针和整数



我正在编写一些将虚拟地址映射到物理地址的代码。

我有以下代码:

if (address > 0xFFFF)
   Status = XST_FAILURE; // Out of range
else if (address <= 0xCFFF || address >= 0xD400) {
   // Write to OCM
   Xil_Out8(OCM_HIGH64_BASEADDR + OCM_OFFSET + address, data);
else { // (address >= 0xD000)
   // Write to external CCA
   Status = ext_mem_write(address, data);

我收到编译器警告: comparison between pointer and integer [enabled by default]

意识到我正在比较两种不同的类型(指针和整数),但这是一个问题吗? 毕竟,将指针与整数进行比较正是我想要做的。

定义要比较的指针常量而不是整数会更干净吗?

const int *UPPER_LIMIT = 0xFFFF;
...
if (address > UPPER_LIMIT ){
    ....

干净的方法是使用类型 uintptr_t 的常量,它被定义为一个无符号整数,可以在指针和整数之间唯一地映射。

这应该由 #include <stdint.h> 定义。 如果未定义,则表示编译器不遵循 C 标准,或者系统没有平面内存模型。

它打算以"明显"的方式映射,即每个字节按升序排列一个整数。该标准并不能绝对保证这一点,但作为一个实施质量问题,很难看到任何其他事情发生。

例:

uintptr_t foo = 0xFFFF;
void test(char *ptr)
{
    if ( (uintptr_t)ptr < foo )
         // do something...
}

这是由C标准明确定义的。 使用 void * 而不是 uintptr_t 的版本是未定义的行为,但如果编译器不太激进,它似乎可以工作。

这可能

就是为什么Linux内核使用unsigned long作为地址的原因(注意区别 - 指针指向一个对象,而地址是表示内存中位置的抽象代码)。

从编译器的角度来看,这就是它的样子:

  1. C 标准没有定义如何比较int(算术类型)文字0xFFFF和指针address -- 见第 6.5.8
  2. 因此,它必须以某种方式转换操作数。这两种转换都是按第6.3.2.3段状态定义的实现。以下是编译器有资格做出的几个疯狂决定:
    • 因为0xFFFF可能是int的——参见 6.4.4,它可能会强制指针指向 int,如果sizeof(int) < sizeof(void*),你将丢失更高的字节。
    • 我可以想象更疯狂的情况,当0xFFFF符号扩展到0xFFFFFFFF(不应该,但为什么不呢)

当然,(2)都不应该发生,现代编译器足够聪明。但它可能会发生(我假设你正在编写嵌入的东西,它更有可能发生),所以这就是编译器发出警告的原因。

这里有一个"疯狂的编译器事情"的实际例子:在GCC 4.8中,优化器开始将整数溢出视为UB(未定义的行为),并省略指令,假设程序员不希望整数溢出:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61569

我指的是N1570 - C11标准草案

将指针投射到无符号 int 以避免警告:(unsigned)address - 在 32 位或 16 位地址空间的情况下。

最新更新