gpt4 book ai didi

c - 对已经寻址数组基址的指针应用后递减会调用未定义的行为吗?

转载 作者:太空狗 更新时间:2023-10-29 17:10:31 27 4
gpt4 key购买 nike

在寻找有关以下内容的相关或重复问题无济于事之后(我只能做边际正义来描述用 C 标记的指针算术和后递减问题的绝对数量,但足以说“船载”对那个结果集计数有严重的不公正)我把它扔在戒指中希望得到澄清或转介到一个我没有找到的副本。

如果将后递减运算符应用于如下指针(数组序列的简单反向迭代),则以下代码是否会调用未定义的行为?

#include <stdio.h>
#include <string.h>

int main()
{
char s[] = "some string";
const char *t = s + strlen(s);

while(t-->s)
fputc(*t, stdout);
fputc('\n', stdout);

return 0;
}

最近有人向我提议 6.5.6.p8 加法运算符与 6.5.2.p4 后缀递增和递减运算符一起指定甚至执行 t 时的后递减它已经包含 s 的基地址调用未定义的行为,无论是否评估 t 的结果值(不是 t-- 表达式结果)。我只是想知道是否确实如此。

标准中引用的部分是:

6.5.6 Additive Operators

  1. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

及其与...的紧密耦合关系

6.5.2.4 Postfix increment and decrement operators Constraints

  1. The operand of the postfix increment or decrement operator shall have atomic, qualified, or unqualified real or pointer type, and shall be a modifiable lvalue.

Semantics

  1. The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand. With respect to an indeterminately-sequenced function call, the operation of postfix ++ is a single evaluation. Postfix ++ on an object with atomic type is a read-modify-write operation with memory_order_seq_cst memory order semantics.98)

  2. The postfix -- operator is analogous to the postfix ++ operator, except that the value of the operand is decremented (that is, the value 1 of the appropriate type is subtracted from it).

Forward references: additive operators (6.5.6), compound assignment (6.5.16.2).

在发布的示例中使用后递减运算符的真正原因是为了避免评估针对数组基地址的最终无效地址值。例如,上面的代码是对以下代码的重构:

#include <stdio.h>
#include <string.h>

int main()
{
char s[] = "some string";

size_t len = strlen(s);
char *t = s + len - 1;
while(t >= s)
{
fputc(*t, stdout);
t = t - 1;
}
fputc('\n', stdout);
}

暂时忘记它有一个 s 的非零长度字符串,这个通用算法显然有问题(可能对某些人来说不是那么清楚)。如果 s[] 改为 "" ,则 t 将被分配一个值 s-1 ,它本身不在 s 通过其过去地址的有效范围内,并且随之而来的与 s 进行比较的评估是不好的。如果 s 的长度不为零,则可以解决初始 s-1 问题,但只是暂时的,因为最终这仍然依赖于该值(无论它是什么)对与 s 比较以终止循环。还可能会更糟糕的。它可能天真地是:

    size_t len = strlen(s) - 1;
char *t = s + len;

如果 s 是一个零长度的字符串,这将是一个灾难。这个问题的重构代码是为了解决所有这些问题。但是……

我的偏执狂可能会影响到我,但如果他们真的全力以赴来抓你,那这就不是偏执狂。那么,根据标准(这些部分,或者其他部分),原始代码(如果您现在忘记它的样子,请滚动到这本小说的顶部)是否确实调用了未定义的行为?

最佳答案

我很确定在这种情况下后递减的结果确实是未定义的行为。后递减显然从指向对象开头的指针中减去一个,因此结果不指向同一数组的元素,并且根据指针算术的定义(§6.5.6/8,如引用OP) 这是未定义的行为。您从不使用结果指针这一事实无关紧要。

有什么问题:

char *t = s + strlen(s);
while (t > s) fputc(*--t, stdout);

有趣但无关紧要的事实:标准 C++ 库中反向迭代器的实现通常在反向迭代器中保存一个指向目标元素之后的指针。这允许反向迭代器正常使用,而无需涉及指向容器“开始前的一个”的指针,如上所示,这将是 UB。

关于c - 对已经寻址数组基址的指针应用后递减会调用未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30512669/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com