指针与非零整数的不等比较曾何时合法?C++标准中如何规定?
关于指针与非零整数不等比较的C++标准历史问题
编译背景与错误信息
在Win10 x64系统的MSYS2环境下编译Seven Kingdoms: Ancient Adversaries项目2.15.5版本时,使用编译命令:
./configure --prefix=/dbg CPPFLAGS=-DDEBUG CFLAGS="-g -O0" && make
出现如下编译错误:
In file included from ../include/ALL.h:33, from OCOLTBL.cpp:25: OCOLTBL.cpp: In member function 'void ColorTable::generate_table(int, PalDesc&, RGBColor (*)(RGBColor, int, int))': OCOLTBL.cpp:194:54: error: ordered comparison of pointer with integer zero ('BYTE*' {aka 'unsigned char*'} and 'int') 194 | err_when(absScale < 0 || palD.reserved_color < 0 || palD.pal == NULL); | ~~~~~~~~~~~~~~~~~~~~^~~ ../include/OERROR.h:52:32: note: in definition of macro 'err_when' 52 | #define err_when(cond) if(cond) err.internal(NULL,__FILE__, __LINE__) | ^~~~
其中palD.reserved_color的类型为unsigned char *。
核心疑问
- 指针与非零整数的不等比较曾在何时合法?
- 当时C++标准中如何处理?
- 过去
ptr < 0这类表达式如何工作? - 最后一次合法时标准的定义是什么?
问题解答
1. 合法时期
早期C标准(C98/C03)以及更早的C标准(C89/C90)允许指针与整数进行包括不等比较在内的各类比较操作。从C11开始,指针与非零整数的不等比较被明确列为未定义行为,现代编译器会直接报错或发出严重警告。
2. 早期标准的处理方式
在C98/C03中:
- 指针可以隐式转换为
std::ptrdiff_t(一种有符号整数类型,用于表示两个指针之间的差值); - 整数也可以转换为指针类型,但仅当整数是0时行为定义明确,非零整数转换为指针属于实现定义行为;
- 当执行
ptr < 0这类比较时,实际是先将指针转换为std::ptrdiff_t类型,再与整数0进行比较。
3. ptr < 0的实际工作逻辑
在早期的实模式或分段内存模型(比如DOS时代的16位系统)中,指针通常包含段地址和偏移地址两部分。某些内存模型下,偏移地址使用有符号整数表示(如16位有符号整数),此时ptr < 0可以用来判断指针的偏移部分是否为负数,对应内存中的低地址区域。但在现代平坦内存模型(如x86_64)中,指针是无符号的64位值,ptr < 0的结果永远为假,这类比较完全没有实际意义。
4. 最后一次合法的标准定义
C++03是最后允许这类比较的官方标准,其相关条款定义如下:
指针可以与整数类型的值进行比较。指针转换为整数类型的结果是实现定义的。除了指针可以与值为0的整数常量表达式比较外,其他指针与整数的比较结果是实现定义的。
内容的提问来源于stack exchange,提问作者Zsar
相关产品推荐
相关产品推荐

