一行中的多个赋值

ris*_*scy 24 c embedded

我刚刚看到嵌入式c语句(dsPIC33)

sample1 = sample2 = 0;
Run Code Online (Sandbox Code Playgroud)

这意味着什么

sample1 = 0;

sample2 = 0;
Run Code Online (Sandbox Code Playgroud)

他们为什么这样输入?这是好还是坏编码?

Som*_*ude 38

请记住,赋值是从右到左完成的,它们是正常的表达式.所以从编译器的角度来看

sample1 = sample2 = 0;
Run Code Online (Sandbox Code Playgroud)

是相同的

sample1 = (sample2 = 0);
Run Code Online (Sandbox Code Playgroud)

这是一样的

sample2 = 0;
sample1 = sample2;
Run Code Online (Sandbox Code Playgroud)

也就是说,sample2被赋值为零,然后sample1被赋值为sample2.在实践中,就像你猜到的那样将两者分配给零.

  • 值得注意的是,这个表达式中没有排序.这意味着假设首先分配`sample2`并且从`sample2`读取分配给`sample1`的值是不正确的.更准确地说,`sample1`被赋值为`0`转换为`sample2`的类型.并且`sample1`的赋值实际上可以在赋值给`sample2`之前发生. (7认同)
  • 对此,我要补充一点,`sample2 = 0`返回的rvalue等于`sample2`中指定的值.所以它是一个赋值语句,并且还有一个返回值,等于它赋值的值.返回值(rvalue)是指定给`sample1`的值. (4认同)
  • 感谢您的回复,我会以 AndreyT 中强调的可读性和排序问题的名义避免sample1=sample2=0。 (2认同)

AnT*_*AnT 9

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

T t;
U u;
Run Code Online (Sandbox Code Playgroud)

分配

t = u = X;
Run Code Online (Sandbox Code Playgroud)

(X某些值在哪里)被解释为

t = (u = X);
Run Code Online (Sandbox Code Playgroud)

并相当于一对独立的任务

u = X;
t = (U) X;
Run Code Online (Sandbox Code Playgroud)

X应该注意,值应该到达变量t"好像"它u首先通过变量,但是没有要求它实际上以这种方式发生.X只需在转移u之前转换为类型t.该值不必先分配给u,然后从中复制ut.上述两个任务实际上没有排序,可以按任何顺序发生,这意味着

t = (U) X;
u = X;
Run Code Online (Sandbox Code Playgroud)

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

没有更多的背景,没有办法说是一个好的或坏的编程实践.如果两个变量紧密相关(如点xy坐标),使用"链式"赋值将它们设置为某个常用值实际上是非常好的练习(我甚至会说"推荐练习").但是当变量完全不相关时,将它们混合在一个"链式"赋值中绝对不是一个好主意.特别是如果这些变量具有不同的类型,这可能导致意想不到的后果.


小智 6

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

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

int main() {
        int a, b, c, d;
        a = b = c = d = 0;
        return a;
}
Run Code Online (Sandbox Code Playgroud)

我有这个装配(Kubuntu,gcc 4.8.2,x86_64)-O0当然有选项;)

main:
        pushq   %rbp
        movq    %rsp, %rbp

        movl    $0, -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
Run Code Online (Sandbox Code Playgroud)

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

  • 编译器可以自由地进行任何代码转换,但不会改变可观察的行为.因此,组装通常没有任何证据.您唯一可以依赖的是c ++标准规范(如果编译器承诺遵守标准). (4认同)