下面的代码是有效的C吗? (空指针的指针算术)

问题描述 投票:0回答:1

我最近一直在阅读 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 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则求值不会产生溢出;否则,行为是未定义的。如果结果指向数组对象的最后一个元素,则不得将其用作所计算的一元 * 运算符的操作数。

除了数组上的算术行为之外,我还理解这条规则也描述了由于空指针不指向任何对象,所以对它们进行算术是未定义的行为。 (我发现与此相关的Reddit 帖子支持了我的结论)

首先:我对上述说法的理解正确吗?

其次:下面的代码怎么样?这是否也被视为 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 节无效
  • 第 6.2.5 节类型)- 规则 [1,19,20,28]
提前感谢您的帮助!

c pointers undefined-behavior pointer-arithmetic c17
1个回答
0
投票

intptr_t

 只是一个普通的有符号整数类型。您可以像任何其他整数一样使用它,有关指针的规则不适用于它。

它的特别之处(以及

uintptr_t

)是它保证足够大以容纳任何
void*
指针(并且由于任何对象指针都可以转换为
void*
而不会丢失任何信息,这也意味着它是足够大以容纳任何对象指针)。因此,您可以将指针投射到 
intptr_t
,然后将结果投射回来,并获取原始指针。

但是,如果您修改

intptr_t

 变量的值,则没有这样的保证。以下未定义:

int arr[2] = {0, 1}; intptr_t iptr = (intptr_t) arr; iptr += sizeof(int); int *ptr = (int *)iptr; printf("%d\n", *ptr);
在大多数实现中,我希望打印出 

1

,但这不是规范所要求的。

© www.soinside.com 2019 - 2024. All rights reserved.