在 for 循环中指向数组开头之前

so.*_*red 2 c language-lawyer

考虑以下 C 代码:

for (data_object_t *first = get_first(dev),
                   *last  = first + get_num_of_data_objects(dev) - 1,
                   *curr  = first;
                    curr <= last;
                    curr++) {
        // process *curr
    }
Run Code Online (Sandbox Code Playgroud)

假设get_first()返回一个指向位于某个大数组中的对象的指针data_object_t,并且get_num_of_data_objects()永远不会返回会导致越界访问的值。

get_num_of_data_objects()我的问题具体是关于返回 0 的情况。
在这种情况下,lastwill 是first - 1,所以我希望简单地跳过循环(因为curr <= last从一开始就评估为 false ),但困扰我的是有可能last指向数组开头之前
,这让我想知道 - 即使它没有被取消引用: 这是一个不好的做法吗?
这里是否存在未定义行为的可能性?

dbu*_*ush 6

如果first指向数组的开头,first - 1则尝试创建指向数组开头之前的指针。在这种情况下, 的行为first - 1未定义的

\n

C 标准第 6.5.6p8 节详细说明了有关指针加法和减法的规则:

\n
\n

当整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向距原始元素的元素偏移量,使得结果数组元素和原始数组元素的下标之差等于整数表达式。\n换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N(相当于 N+(P))和 (P)-N\n(其中 N 的值 n) 分别指向数组对象的第 i+n 个和\ni\xe2\x88\x92n 个元素(前提是它们存在)。此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象最后一个元素的最后一个元素,并且如果表达式 Q 指向数组对象最后一个元素的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素。 array\nobject,表达式 (Q)-1 指向 array\nobject 的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则求值不会产生溢出;否则,\n行为是未定义的。如果结果指向数组对象的最后一个元素,则不得将其用作所计算的一元运算符的操作数。

\n
\n

这些规则不允许在数组开头之前创建指针。

\n

然而,它们允许的是拥有一个指向数组末尾之后的一个元素的指针(尽管它不能被取消引用)。因此,您可以使用它来修改循环,如下所示:

\n
for (data_object_t *first = get_first(dev),\n                   *last  = first + get_num_of_data_objects(dev),\n                   *curr  = first;\n                    curr < last;\n                    curr++) {\n        // process *curr\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

  • @Ágatha不,该标准明确指出,使用指针算术产生这样的指针是未定义的行为。请参阅https://port70.net/~nsz/c/c11/n1570.html#6.5.6p8 (3认同)