在C语言中复制字符串

7
我对这段代码感到困惑:(http://www.joelonsoftware.com/articles/CollegeAdvice.html)
while (*s++ = *t++);

执行顺序是什么?先执行`s=*t`,再递增各自的值吗?还是相反?谢谢。
编辑:如果代码变成这样呢?
while(*(s++) = *(t++));

并且

while(++*s = ++*t);

1
我想知道Joel是否仍然支持那篇五年前的文章... Joel,你愿意发表评论吗? - Hogan
我建议每个人在while循环中,当循环体为空语句时,将分号放在下一行而不是仅在循环条件后面。我真的认为这样更清晰、更易读。 - Thomas Padron-McCarthy
7个回答

14
while (*s++ = *t++);

优先级表可以清楚地看到++的优先级高于*。但是++在这里被用作后缀递增运算符,因此递增发生在赋值表达式之后。因此,*s = *t首先发生,然后s和t递增。
while(*(s++) = *(t++));

与上面相同。使用括号使其更明确。但请记住++仍然是后增量。

while(++*s = ++*t);

在s旁边只有一个运算符。所以先应用*,然后在该结果上应用++,导致出现需要lvalue错误。

while(*++s = *++t);

再次,操作符位于s,t旁边。因此,增量操作首先发生,然后是复制。因此,我们有效地跳过了将t的第一个字符复制到s的步骤。

难道不是“precedence”而不是“precedance”吗?这可能是英国/美国的一些差异,所以我不想编辑... - Thomas Padron-McCarthy

4

你说得对。*s = *t 首先被执行,然后它们被递增。


2
递增是后递增,不仅因为它在递增的变量之后出现,而且因为它在表达式计算后出现。因此,执行顺序是:
*s = *t

然后 s++ 和 t++


1

编辑:

@chrisgoyal

执行顺序是一个模糊的术语。这里有两个不同的事情。语法顺序和表达式的语义。

从语法上讲,运算符++首先被应用。如果*s首先被应用,则以下内容等同于@Hogan所说的:

(*s)++ = (*t)++

这与Joel的示例非常不同。

运算符++的语义是在表达式之后执行。

希望这澄清了我的意思。


实际上,先执行了 s++t++。不要忘记后缀运算符是在表达式完成后执行的。基本上,运算符 ++ 适用于两者,然后执行 *s = *t

错误... after 意味着之后。你描述的增量发生在之前。 - Hogan
@Hogan 后缀运算符的优先级更高,因此它首先被应用。后缀运算符的语义是在表达式完成之后应用的。 - Khaled Alshaya
不完全正确。++(前缀或后缀)的优先级高于=,因此它会“先发生” - 只是后缀++返回旧值而不是新递增的值。机器代码中实际发生操作的时间无关紧要。 - Chris Lutz
现在完全清楚了...-1被放逐。(虽然有超过16k,但不确定这是否是一个大问题。) - Hogan

0

所以有两种形式的递增

++s // increment before using value
s++ // increment after using value

这些的结果可以被取消引用:

*++s // or...
*s++

在C语言的最早期机器之一PDP-11上,这个方法非常有效,因为它具备寄存器间接寻址模式并可以在操作寄存器后自动递增。以下操作均可在硬件中使用:

*--s // or
*s++

你可以选择任何一种方式

*x++ = *y++; // or
*--x = *--y; // or some combination

如果你这样做了,整行代码将在一条指令中完成。然而,由于//注释是由C99引入的,因此你实际上不能使用我的注释语法。


你可以在99%的C编译器中使用//注释,虽然这不是一个好主意,但我怀疑它不会伤害任何人。 - Chris Lutz
像往常一样,你是正确的,我完全同意,但我在推测他们可能没有在PDP-11 C编译器上工作... - DigitalRoss

0
代码:(while *s++ = *t++); 大致相当于:
while (*s = *t) {
    ++s;
    ++t;
}

第二个例子完全相同——多余的括号在这种情况下不会改变任何东西。要使括号起作用,它们必须像这样:while ((*s)++ = (*t)++);。这将大致执行与您的第三个示例相同的操作(在下面的段落中介绍)。

最后一个例子:while(++*s = ++*t);则完全不同。由于解引用符(*)更接近操作数,因此这会对操作数进行解引用,并增加解引用结果,这意味着它会增加指针所指向的内容,而不是增加指针本身。因此,这将复制第一个字符,然后增加该字符,然后检查该字符是否为非零,并继续执行相同的操作,直到它为零。结果将是源和目标都变成空字符串(因为两者的第一个字符现在都是零,用于终止字符串)。


0

在后置递增操作中,变量先被使用,然后再被修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接