3

§5.1.2.4.16

示例 7 表达式的分组并不能完全确定它的求值。在以下片段中:

#include <stdio.h>
int sum;
char *p;
/*
...
*/
sum = sum * 10 - '0' + (*p++ = getchar());

表达式语句被分组,就好像它被写成

sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));

但是 p 的实际增量可以发生在前一个序列点和下一个序列点( ; )之间的任何时间,并且对 getchar 的调用可以在需要其返回值之前的任何时间发生。

所以基本上我将其理解为未指定的行为-要​​么*p = getchar(); p++;OR p++; *p = getchar()。请注意,这;意味着一个序列点,但整个表达式中没有其他序列点。

所以这个语法是没用的。而且,对于指针赋值,++ 和 -- 几乎是没用的。正确的?

4

4 回答 4

6

要么[*p = getchar(); p++;原文p++; p* = getchar() ]

好吧实际上没有。它是:

*p = getchar(); p++

或者

old_p = p++; *old_p = getchar()

在您的解释中,您可以写在*p*(p + 1)不正确。在这两种解释中,您写入p最初指向的位置,而不管编译器何时决定放置更改的指令p。如果它决定将它放在写入之前*p,那么它必须确保它保留旧值以便以后写入 ( *old_p)。

后缀--++运算符实际上是相当不错的捷径。举个例子:

size_t strlen(const char *str)
{
    size_t len = 0;
    while (str[len++]);
    return len - 1;
}

这是strlen使用 suffix的一个非常简洁的实现++


从 C11,6.5.2.4.2(强调我的):

后缀 ++ 运算符的结果是操作数的值。作为副作用,操作数对象的值会递增(即,将相应类型的值 1 添加到其中)。有关约束、类型和转换以及操作对指针的影响的信息,请参阅加法运算符和复合赋值的讨论。结果的值计算在更新操作数的存储值的副作用之前排序。对于不确定顺序的函数调用,后缀 ++ 的操作是单次求值。原子类型对象上的后缀 ++ 是具有 memory_order_seq_cst 内存顺序语义的读-修改-写操作。

于 2013-04-29T10:10:48.390 回答
6

词汇分组无关紧要。重要的是的价值p++

该语句与以下两个语句相同:

sum = sum * 10 - '0' + (*p = getchar());
++p;
于 2013-04-29T10:01:37.593 回答
3
sum = (((sum * 10) - '0') + ((*(p++)) = (getchar())));

相当于

*p = getchar();
sum = ( ((sum * 10) - '0') + *p );
p++;

它减少到1行。这不是没用的,因为以这种方式编写代码可以减少代码的大小和复杂性

sum = (((sum * 10) - '0') + ((*(++p)) = (getchar())));

相当于

p++;
*p = getchar();
sum = ( ((sum * 10) - '0') + *p );
于 2013-04-29T10:01:57.113 回答
0

使用 -- 和 ++ 进行指针赋值实际上并不是没用的。考虑一个要读取 10 个字符并在末尾添加转义字符的循环:

int i, sum;
char * p;
p = (char*) malloc(11 * sizeof(char));

for (i = 0; i < 10; i++){
   sum = sum * 10 - '0' + (*p++ = getchar());
}
*p = '\0';
于 2013-04-29T10:10:37.090 回答