gat*_*sec 3 c standards pointers pointer-arithmetic language-lawyer
我注意到Clang的这个警告:
warning: performing pointer arithmetic on a null pointer
has undefined behavior [-Wnull-pointer-arithmetic]
Run Code Online (Sandbox Code Playgroud)
详细信息,正是此代码触发此警告:
uint8_t *end = ((uint8_t*)0) + sizeof(uint8_t) * count;
Run Code Online (Sandbox Code Playgroud)
为什么在从不同于零的整数获得的非空指针上执行相同操作时禁止对空指针进行算术运算不会触发任何警告?
更重要的是,C标准是否明确禁止空指针算法?
C标准不允许.
6.5.6加法运算符(强调我的)
8当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式.换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)指向分别为数组对象的第i + n和第th个元素,只要它们存在即可.此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素.如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数.
出于上述目的,指向单个对象的指针被视为指向1个元素的数组.
现在,((uint8_t*)0)
不指向数组对象的元素.仅仅因为持有空指针值的指针不指向任何对象.对此说:
6.3.2.3指针
3如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.
所以你不能对它进行算术运算.警告是合理的,因为正如第二个突出显示的句子所提到的那样,我们处于未定义的行为的情况.
不要被offsetof
宏可能像这样实现的事实所迷惑.标准库不受用户程序约束的约束.它可以运用更深入的知识.但是在我们的代码中这样做并没有明确定义.