关于C标准中空指针算术及intptr_t运算的合规性问询
关于C语言标准ISO/IEC 9899:2018的指针算术问题
背景说明
近期研读了C语言标准ISO/IEC 9899:2018,其中第6.5.6节(加法运算符)的规则[8]对+运算符的约束作出了如下规定:
当整数类型表达式与指针相加或相减时,结果类型为指针操作数的类型。若指针操作数指向数组对象的某一元素,且数组足够大,则结果指向与原元素偏移量等于整数表达式的元素。换言之,若表达式P指向数组对象的第i个元素,则表达式(P)+N(等价于N+(P))和(P)-N(N的值为n)分别指向数组对象的第i+n个和第i−n个元素(前提是这些元素存在)。此外,若表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后的位置;若表达式Q指向数组对象的最后一个元素之后的位置,则表达式(Q)-1指向数组对象的最后一个元素。若指针操作数与结果均指向同一数组对象的元素或最后一个元素之后的位置,则求值不得产生溢出;否则,行为为未定义。若结果指向数组对象的最后一个元素之后的位置,则不得将其作为被求值的一元
*运算符的操作数。
基于此规则,我认为空指针不指向任何对象,对其进行算术运算属于未定义行为(UB),相关讨论也支持此结论。
提出的问题
- 我对上述规则的理解是否正确?
- 下方代码是否属于未定义行为?若是或若否,请说明原因;第6.5.6节的规则是否适用于
intptr_t?该代码似乎未违反第6.3.2.3节(指针)的规则。
代码片段
int arr[2] = {0}; intptr_t ptr_0 = 0; intptr_t ptr = (intptr_t) arr; intptr_t new = ptr_0 + ptr; int* ptr_int = (int*) new;
补充参考章节
- 第6.3.2.3节(指针)- 规则[1-6]
- 第6.3.2.2节(void类型)
- 第6.2.5节(类型)- 规则[1,19,20,28]
问题解答
1. 规则理解的正确性
你的理解完全正确。第6.5.6节规则[8]明确限定了指针与整数运算的合法场景:仅当指针指向数组对象的元素(或数组末尾之后的一个合法位置)时,这类算术运算的行为才被标准定义。空指针不指向任何对象(包括数组),因此对空指针执行算术运算完全符合规则中"否则,行为为未定义"的描述,属于未定义行为。
2. 代码的未定义行为判定
这段代码不存在未定义行为,原因如下:
- 第6.5.6节的规则仅适用于指针与整数的混合运算,而代码中的
ptr_0 + ptr是两个intptr_t类型(整数类型)的加法,属于普通整数运算,不受第6.5.6节的约束,完全符合整数运算的标准规则。 - 关于指针与
intptr_t的转换:根据第6.3.2.3节的规则,指向对象的指针可以转换为intptr_t(实现定义行为,主流编译器均支持);反之,intptr_t类型的值转换回指针类型时,只要原指针值是有效的(如代码中ptr是数组arr的地址),转换后的指针也会指向原对象,这一转换是合法的。 - 代码中最终得到的
ptr_int等价于arr,是指向数组首元素的有效指针,没有违反任何标准规则。
内容的提问来源于stack exchange,提问作者Rayan
相关产品推荐
相关产品推荐

