简体   繁体   English

在C中的while循环条件中使用赋值运算符

[英]Using the assignment operator in a while loop condition in C

The question is: 问题是:

Rewrite the following C code in a more readable style: 以更易读的方式重写以下C代码:

while (*dst++ = *src++);

I want to check that I am understanding this line correctly. 我想检查一下我是否正确理解了这一行。 By assigning *src to *dst, it is checking if *dst (and, by extension, *src) is a non-zero (or zero) value. 通过将* src分配给* dst,它检查* dst(并且,通过扩展名,* src)是否为非零(或零)值。 If non-zero, the while body is executed, otherwise it is skipped. 如果非零,则执行while主体,否则跳过它。

My answer, based on the above understanding: 基于以上理解,我的回答是:

*dst = *src;
while (*dst) {
   [do stuff]
   *dst++;
   *src++;
   *dst = *src;
}

I realize that the position of the post-increment for both variables is important for a real program, but I don't think it matters here. 我意识到两个变量的后增量位置对于实际程序很重要,但我认为这并不重要。

Yes this is exactly what is being done ( char s are copied along with null terminator) on the one-line code. 是的,这正是在单行代码上完成的工作( char与空终止符一起复制)。 But in your code 但是在你的代码中

*dst++;
*src++;

can be replaced by 可以替换为

dst++;
src++;

You have dereferenced it unnecessarily . 不必要地取消引用它

To explain a bit further the value assigned is the value of the assignment expression which is being checked in the while condition which when turns out to be \\0 terminates the loop but the \\0 is copied in the dst also. 为了进一步解释,分配的值是在while条件中检查的赋值表达式的值,当转换为\\0终止循环,但是也在dst复制\\0

The implementation you wrote also will do one check and one assignment even if it is empty string just like the original one. 您编写的实现也会执行一次检查和一次分配,即使它是空字符串就像原始字符串一样。

And yes in your case, the post increment or pre increment doesn't matter but in original implementation it does . 在你的情况下是的,后增量或预增量并不重要,但在原始实现中它确实如此

By the last line I meant, ++dst;++src; 我的意思是最后一行, ++dst;++src; will be same as dst++;src++; dst++;src++; in your case. 你的情况下。

But in original implementation if you have used 但是在最初的实施中如果你已经使用过

*++dst = *++src

This would be wrong and meaningless for the purpose of copying. 对于复制而言,这是错误的,毫无意义的。 Think of the case when it is empty string. 想想它是空字符串的情况。 You will access array index out of bound. 您将访问数组索引超出范围。


 while(*dst++ = *src++); 

This is readable - in fact for the second code you wrote I have to think twice of the edge cases - here it is clean simple logic. 这是可读的 - 事实上,对于您编写的第二个代码,我必须考虑边缘情况的两倍 - 这里是简洁的简单逻辑。 Less code Less confusion. 减少代码减少混淆。 Readability doesn't mean more code - it is the clean code which is more readable. 可读性并不意味着更多的代码 - 更干净的代码更具可读性。

As you may know, the original loop is a common C idiom for copying a zero-terminated string. 您可能知道,原始循环是用于复制以零结尾的字符串的常见C语言。 Any C programmer should recognize it at a glance. 任何C程序员都应该一目了然。 So in that sense it it already quite readable. 所以在这个意义上它已经非常可读了。

The revised version is harder to understand, with the repeated assignment outside and inside the loop. 修改后的版本更难理解,循环外部和内部重复分配。

If you want to write it out step by step in the most detailed manner possible, while also keeping exactly the same behavior as the original, I suggest this, assuming that src and dst are char* pointers. 如果你想以尽可能详细的方式逐步写出来,同时也保持与原始行为完全相同的行为,我建议这一点,假设srcdstchar*指针。

// This extra pair of curly braces keeps the `char c` local to this code
{
    char c;  // Change this if the type is different
    do {
        c = *src;
        *dst = c;
        src = src + 1;
        dst = dst + 1;
    } while( c );
}

BTW one problem with the original is that many modern C compilers will issue a warning on the assignment, the idea being that it may be a typo for an intended == comparison. 顺便说一下原来的一个问题是许多现代C编译器会对赋值发出警告,这个想法可能是对于预期的==比较可能是一个错字。 You can usually suppress this warning with an extra set of parentheses: 您通常可以使用一组额外的括号来抑制此警告:

while(( *dst++ = *src++ )) ;
   *dst++;
   *src++;

is same as 和...一样

   *dst; <<dereferencing for no use. 
    dst++;  
   *src; <<dereferencing for no use.
    src++;

By assigning *src to *dst, it is checking if *dst (and, by extension, *src) is a non-zero (or zero) value. 通过将* src分配给* dst,它检查* dst(并且,通过扩展名,* src)是否为非零(或零)值。 If non-zero, the while body is executed, otherwise it is skipped. 如果非零,则执行while主体,否则跳过它。

That's correct as far as it goes, but as far as the purpose of such code goes, it misses the point. 这是正确的,但就这些代码的目的而言,它错过了重点。 A high-level description of the function of the code would be: copy successive elements of the array pointed into by src to successive elements of the array pointed into by dst until an element with value 0 has been copied. 代码功能的高级描述是:将src指向的数组的连续元素复制到dst指向的数组的连续元素,直到复制了值为0的元素。 In particular, if src and dst are pointers to char then this is a possible implementation of the strcpy() function. 特别是,如果srcdst是指向char指针,那么这是strcpy()函数的可能实现。

But your characterization does not describe all the effects of the code, which include incrementing the src and dst pointers to one position past the last element copied. 但是你的表征并没有描述代码的所有影响,包括将srcdst指针递增到复制的最后一个元素之后的一个位置。 Your version does not match this. 您的版本与此不符。 Moreover, your version is a bit odd in how it performs the pointer increments, in that after it performs the increments, it pointlessly dereferences the new pointer values and ignores the results. 此外,您的版本在执行指针增量方面有点奇怪,因为在执行增量之后,它无意义地取消引用新指针值并忽略结果。 That's not good style. 不是好风格。

There are a lot of alternatives that I would consider more readable, but your instructor may be looking for some particular characteristics. 有许多替代方案我认为更具可读性,但您的教练可能正在寻找一些特定的特征。 I expect first of all that they would want a version that does not use an assignment expression in boolean context. 我首先要求他们想要一个不在布尔上下文中使用赋值表达式的版本。 I imagine that they would also want to see the pointer dereferences and pointer increments performed in separate expressions. 我想他们也希望看到指针取消引用和指针增量在单独的表达式中执行。 Here's a version that has those characteristics, that produces all the side effects of the original code, and that minimizes code duplication: 这是一个具有这些特性的版本,它产生原始代码的所有副作用,并最大限度地减少代码重复:

do {
    *dst = *src;
    dst++;
    src++;
} while (*(src - 1));

Your understanding of what the loop does is correct, but not your understanding of the post-increment, the post-increment has higher precedence than the *, so in the original while loop the post-increment increments the pointers (returning the original values), then dereferences those pointers assigning original *src to original *dest. 你对循环的作用的理解是正确的,但不是你理解后增量,后增量的优先级高于*,所以在原始的while循环中,后增量会增加指针(返回原始值) ,然后取消引用那些将原始* src分配给原始* dest的指针。

I suggest doing it as a for loop (although the original is already highly idiomatic): 我建议将它作为for循环(虽然原来已经非常惯用):

for( ; *dst = *src; ++dst, ++src)
{ }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM