是否定义了两个非void指针变量(根据C99和/或C++ 98)的差异NULL?
例如,假设我有一个如下所示的缓冲区结构:
struct buf {
char *buf;
char *pwrite;
char *pread;
} ex;
Run Code Online (Sandbox Code Playgroud)
比如说,ex.buf指向一个数组或一些malloc的内存.如果我的代码始终保证pwrite和pread点阵列中或一个过去,然后我相当有信心,ex.pwrite - ex.pread总是被定义.但是,如果pwrite和pread都是NULL.我可以只期望减去两个定义为(ptrdiff_t)0或严格兼容的代码需要测试指针为NULL吗?请注意,我感兴趣的唯一情况是两个指针都是NULL(表示缓冲区未初始化的情况).原因在于满足前面的假设,完全符合"可用"功能:
size_t buf_avail(const struct s_buf *b)
{
return b->pwrite - b->pread;
}
Run Code Online (Sandbox Code Playgroud)
Ada*_*eld 96
在C99中,它在技术上是未定义的行为.C99§6.5.6说:
7)出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型.
[...]
9)当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异.[...]
§6.3.2.3/ 3说:
值为0的整型常量表达式或此类表达式转换为类型
void *称为空指针常量.55)如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.
因此,由于空指针与任何对象不相等,它违反了6.5.6/9的前提条件,因此它是未定义的行为.但实际上,我愿意打赌,几乎每个编译器都会返回0的结果而没有任何不良副作用.
在C89中,它也是未定义的行为,尽管标准的措辞略有不同.
另一方面,C++ 03确实在这个实例中定义了行为.该标准为减去两个空指针做了一个特殊的例外.C++03§5.7/ 7说:
如果将值0添加到指针值或从指针值中减去,则结果将等于原始指针值.如果两个指针指向同一个对象,或者两个指针都指向同一个数组的末尾或两者都为空,并且减去了两个指针,则结果将比较等于转换为该类型的值0
ptrdiff_t.
C++ 11(以及C++ 14的最新草案,n3690)与C++ 03具有相同的措辞,只是std::ptrdiff_t代替了微小的变化ptrdiff_t.
Pub*_*bby 36
我在C++标准(5.7 [expr.add]/7)中找到了这个:
如果两个指针都为空,并且减去了两个指针,则结果比较等于转换为类型std :: ptrdiff_t的值0
正如其他人所说,C99要求两个指针之间的加/减是同一个数组对象.NULL不指向有效对象,这就是为什么不能在减法中使用它.
Jen*_*edt 23
编辑:这个答案仅对C有效,我回答时没有看到C++标签.
不,指针算法仅允许指向同一对象内的指针.由于C标准的定义,空指针不指向任何对象,因此这是未定义的行为.
(虽然,我猜任何合理的编译器都会返回0它,但是谁知道.)