C语言 一行多任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19353686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:42:19  来源:igfitidea点击:

Multiple assignment in one line

cembedded

提问by riscy

I just come across the statement in embedded c (dsPIC33)

我刚刚遇到了嵌入式 c (dsPIC33) 中的语句

sample1 = sample2 = 0;

Would this mean

这是否意味着

sample1 = 0;

sample2 = 0;

Why do they type it this way? Is this good or bad coding?

他们为什么这样打字?这是好还是坏的编码?

回答by Some programmer dude

Remember that assignment is done right to left, and that they are normal expressions. So from the compilers perspective the line

请记住,赋值是从右到左完成的,它们是普通表达式。所以从编译器的角度来看,这条线

sample1 = sample2 = 0;

is the same as

是相同的

sample1 = (sample2 = 0);

which is the same as

这与

sample2 = 0;
sample1 = sample2;

That is, sample2is assigned zero, then sample1is assigned the value of sample2. In practice the same as assigning both to zero as you guessed.

也就是说,sample2被赋值为零,然后sample1被赋值为sample2。实际上,与您猜测的将两者都分配为零相同。

回答by AnT

Formally, for two variables tand uof type Tand Urespectively

从形式上看,两个变量tu类型T,并U分别

T t;
U u;

the assignment

那作业

t = u = X;

(where Xis some value) is interpreted as

(where Xis some value) 被解释为

t = (u = X);

and is equivalent to a pair of independent assignments

并且等价于一对独立的赋值

u = X;
t = (U) X;

Note that the value of Xis supposed to reach variable t"as if" it has passed through variable ufirst, but there's no requirement for it to literally happen that way. Xsimply has to get converted to type of ubefore being assigned to t. The value does not have to be assigned to ufirst and then copied from uto t. The above two assignments are actually not sequenced and can happen in any order, meaning that

请注意, 的值X应该t“就好像”到达变量一样,它u首先通过了变量,但并不要求它确实以这种方式发生。X只需要u在被分配给之前转换为类型t。该值不必先分配给u,然后再从uto复制t。上述两个赋值实际上没有顺序,可以以任何顺序发生,这意味着

t = (U) X;
u = X;

is also a valid execution schedule for this expression. (Note that this sequencing freedom is specific to C language, in which the result of an assignment in an rvalue. In C++ assignment evaluates to an lvalue, which requires "chained" assignments to be sequenced.)

也是此表达式的有效执行计划。(请注意,这种排序自由是特定于 C 语言的,其中右值中的赋值结果。在 C++ 中,赋值计算为左值,这需要对“链式”赋值进行排序。)

There's no way to say whether it is a good or bad programming practice without seeing more context. In cases when the two variables are tightly related (like xand ycoordinate of a point), setting them to some common value using "chained" assignment is actually perfectly good practice (I'd even say "recommended practice"). But when the variables are completely unrelated, then mixing them in a single "chained" assignment is definitely not a good idea. Especially if these variables have different types, which can lead to unintended consequences.

如果不了解更多上下文,就无法判断这是一种好的还是坏的编程实践。在情况下,当两个变量密切相关(如xy点的坐标),使用“链接”的分配实际上是非常好的做法(我甚至说:“建议实践”),将它们设置一些共同的价值。但是当变量完全不相关时,将它们混合在一个“链式”赋值中绝对不是一个好主意。特别是如果这些变量具有不同的类型,这可能会导致意想不到的后果。

回答by hurufu

I think there is no good answer on C language without actual assembly listing :)

我认为没有实际的汇编列表就没有关于 C 语言的好答案:)

So for a simplistic program:

所以对于一个简单的程序:

int main() {
        int a, b, c, d;
        a = b = c = d = 0;
        return a;
}

I've got this assemly (Kubuntu, gcc 4.8.2, x86_64) with -O0option of course ;)

我有这个组件(Kubuntu,gcc 4.8.2,x86_64)-O0,当然可以选择;)

main:
        pushq   %rbp
        movq    %rsp, %rbp

        movl    
sample1 = func() + (sample2 = func());
, -16(%rbp) ; d = 0 movl -16(%rbp), %eax ; movl %eax, -12(%rbp) ; c = d movl -12(%rbp), %eax ; movl %eax, -8(%rbp) ; b = c movl -8(%rbp), %eax ; movl %eax, -4(%rbp) ; a = b movl -4(%rbp), %eax ; popq %rbp ret ; return %eax, ie. a

So gcc is actuallychaining all the stuff.

所以 gcc实际上是链接所有的东西。

回答by kjelderg

The results are the same. Some people prefer chaining assignments if they are all to the same value. There is nothing wrong with this approach. Personally, I find this preferable if the variables have closely related meanings.

结果是一样的。如果它们都具有相同的值,有些人更喜欢链接分配。这种方法没有任何问题。就我个人而言,如果变量具有密切相关的含义,我认为这更可取。

回答by Don't You Worry Child

You can yourself decide that this way of coding is good or bad.

您可以自己决定这种编码方式是好是坏。

  1. Simply see the assembly code for the following lines in your IDE.

  2. Then change the code to two separate assignments, and see the differences.

  1. 只需在 IDE 中查看以下行的汇编代码。

  2. 然后将代码更改为两个单独的分配,并查看差异。

In addition to this, you can also try turning off/on optimizations (both Size & Speed Optimizations) in your compiler to see how that affects the assembly code.

除此之外,您还可以尝试在编译器中关闭/打开优化(大小和速度优化)以查看它如何影响汇编代码。

回答by Lundin

As others have said, the order in which this gets executed is deterministic. The operator precedenceof the = operator guarantees that this is executed right-to-left. In other words, it guarantees that sample2 is given a value before sample1.

正如其他人所说,执行此操作的顺序是确定性的。= 运算符的运算符优先级保证从右到左执行。换句话说,它保证在 sample1 之前给 sample2 一个值。

However, multiple assignments on one row is bad practice and banned by many coding standards (*). First of all, it is not particularly readable (or you wouldn't be asking this question). Second, it is dangerous. If we have for example

但是,在一行上进行多项分配是不好的做法,并且被许多编码标准 (*) 禁止。首先,它的可读性不是特别好(否则你就不会问这个问题了)。其次,它是危险的。如果我们有例如

int tmp1 = func();
int tmp2 = func();
sample2 = tmp2;
sample1 = tmp1 + tmp2;

then operator precedence guarantees the same order of execution as before (+ has higher precedence than =, therefore the parenthesis). sample2 will get assigned a value before sample1. But unlike operator precedence, the order of evaluation of operatorsis not deterministic, it is unspecified behavior. We can't know that the right-most function call is evaluated before the left-most one.

然后运算符优先级保证与以前相同的执行顺序(+ 的优先级高于 =,因此是括号)。sample2 将在 sample1 之前分配一个值。但与运算符优先级不同,运算符的求值顺序不是确定性的,它是未指定的行为。我们无法知道最右边的函数调用在最左边的函数调用之前被评估。

The compiler is free to translate the above to machine code like this:

编译器可以自由地将上述内容转换为机器代码,如下所示:

sample1 = sample2 = 0;

If the code depends on func() getting executed in a particular order, then we have created a nasty bug. It may work fine in one place of the program, but break in another part of the same program, even though the code is identical. Because the compiler is free to evaluate sub-expressions in any order it likes.

如果代码依赖于 func() 以特定顺序执行,那么我们就创建了一个令人讨厌的错误。它可能在程序的一个地方工作正常,但在同一程序的另一部分中断,即使代码是相同的。因为编译器可以按照它喜欢的任何顺序自由地评估子表达式。



(*) MISRA-C:2004 12.2, MISRA-C:2012 13.4, CERT-C EXP10-C.

(*) MISRA-C:2004 12.2, MISRA-C:2012 13.4, CERT-C EXP10-C。

回答by P. B. M.

Regarding coding style and various coding recommendations see here: Readability a=b=c or a=c; b=c;?

关于编码风格和各种编码建议,请参见此处: 可读性 a=b=c 或 a=c;b=c;?

I beleive that by using

我相信通过使用

sample1 = 0;
sample2 = 0;

some compilers will produce an assembly slightly faster in comparison to 2 assignments:

与 2 个赋值相比,某些编译器生成程序集的速度会稍快一些:

sample2 = 0; 
sample1 = sample2;

specially if you are initializing to a non-zero value. Because, the multiple assignment translates to:

特别是如果您要初始化为非零值。因为,多重赋值转化为:

sample1 = sample2 = 0;

So instead of 2 initializations you do only one and one copy. The speed up (if any) will be tiny but in embedded case every tiny bit counts!

因此,您只进行一次和一次复制而不是 2 次初始化。加速(如果有的话)会很小,但在嵌入式情况下,每一点都很重要!

回答by haccks

sample1 = 0;
sample2 = 0;  

does mean

确实意味着

int sample1 = sample2 = 0; //sample1 must be declared before assigning 0 to it

if and only if sample2is declared earlier.
You can't do this way:

当且仅当sample2较早声明。
你不能这样做:

{
    int foo;
}

回答by Nicolas Rapin

Take care of this special case ... suppose b is an array of a structure of the form

注意这个特殊情况……假设 b 是一个结构数组

a = reallocB();
(b + i)->foo = a;

and let i be an offset in b. Consider the function realloc_b() returning an int and performing the reallocation of array b. Consider this multiple assignment:

让我成为 b 中的一个偏移量。考虑函数 realloc_b() 返回一个 int 并执行数组 b 的重新分配。考虑这个多重分配:

a = (b + i)->foo = realloc_b();

a = (b + i)->foo = realloc_b();

To my experience (b + i) is solved first, let us say it is b_i in the RAM ; then realloc_b() is executed. As realloc_b() changes b in RAM, it results that b_i is no more allocated.

根据我的经验 (b + i) 首先解决,让我们说它是 RAM 中的 b_i ;然后 realloc_b() 被执行。由于 realloc_b() 更改了 RAM 中的 b,导致不再分配 b_i。

Variable a is well assigned but (b + i)->foo is not because b as been changed bythe execution of the most left term of the assignment i.e. realloc_b()

变量 a 被很好地赋值,但 (b + i)->foo 不是因为 b 被赋值的最左边一项即 realloc_b() 的执行改变了

This may cause a segmentation fault since b_i is potentially in an unallocated RAM location.

这可能会导致分段错误,因为 b_i 可能位于未分配的 RAM 位置。

To be bug free, and to have (b + i)->foo equal to a, the one-line assignment must be splitted in two assignments:

为了避免错误,并使 (b + i)->foo 等于 a,一行赋值必须拆分为两个赋值:

sample1 = sample2 = 0;

回答by Mephistt

As noticed earlier,

如前所述,

sample2 = 0;
sample1 = sample2;

is equal to

等于

sample2 = 0;
sample1 = 0;

The problem is that riscyasked about embedded c, which is often used to drive registers directly. Many of microcontroller's registers have a different purpose on read and write operations. So, in gereral case, it is not the same, as

问题是riscy询问了嵌入式 c,它通常用于直接驱动寄存器。许多微控制器的寄存器在读写操作上有不同的用途。所以,在一般情况下,它不一样,因为

sample = UDR = 0;

For example, let UDR be a UART data register. Reading from UDR means getting the recieved value from the input buffer, while writing to UDR means putting the desired value into transmit buffer and hitting the communication. In that case,

例如,让 UDR 是一个 UART 数据寄存器。从 UDR 读取意味着从输入缓冲区获取接收到的值,而写入 UDR 意味着将所需的值放入传输缓冲区并进行通信。在这种情况下,

##代码##

means the following: a) transmit value of zero using UART (UDR = 0;) and b) read input buffer and place data into samplevalue (sample = UDR;).

表示以下内容:a) 使用 UART ( ) 传输零值UDR = 0;和 b) 读取输入缓冲区并将数据放入sample值 ( sample = UDR;) 中。

You could see, the behavior of embedded system could be much more complicated than the code writer may expect to be. Use this notation carefully while programming MCUs.

您可以看到,嵌入式系统的行为可能比代码编写者预期的要复杂得多。在对 MCU 进行编程时请谨慎使用此符号。