sample1 = sample2 = 0;
这是否意味着?
sample1 = 0;
sample2 = 0;
为什么他们这样输入呢?这是好的还是坏的编码方式?
sample1 = sample2 = 0;
sample1 = 0;
sample2 = 0;
请记住赋值操作是从右到左进行的,并且它们是正常表达式。因此,从编译器的角度来看,以下这行代码:
sample1 = sample2 = 0;
等同于
sample1 = (sample2 = 0);
就是说
sample2 = 0;
sample1 = sample2;
也就是说,sample2
被赋值为零,然后 sample1
被赋值为 sample2
的值。实际上,和你猜测的一样,这相当于同时将它们都赋值为零。
sample2
,并且分配给 sample1
的值实际上从 sample2
中读取,是不正确的。更正确的说法是,sample1
被赋值为转换为 sample2
类型的值 0
。而且,sample1
的赋值实际上可以在 sample2
赋值之前发生。 - AnT stands with Russiasample2=0
返回一个rvalue,其值等于在sample2
中分配的值。因此,这是一个赋值语句,并且除了分配的值之外还有一个返回值,该返回值等于所分配的值。这个返回值(rvalue)被分配给sample1
。 - Hazem正式地,对于两个类型分别为T
和U
的变量t
和u
T t;
U u;
t = u = X;
(其中X
是某个值)被解释为
t = (u = X);
它等同于一对独立的赋值操作。
u = X;
t = (U) X;
X
的值应该在被赋给变量t
之前“好像”已经通过变量u
传递过去了,但并不一定要确实以这种方式发生。 X
只需要在赋值给t
之前被转换为u
的类型即可。这个值不必先赋给u
,然后从u
复制到t
。上面的两个赋值实际上没有顺序,并且可以以任何顺序发生。t = (U) X;
u = X;
对于这个表达式,is also a valid execution schedule
。请注意,这种顺序自由是特定于C语言的,在C++中,赋值的结果为lvalue,需要对“链接”赋值进行排序。
没有办法在没有看到更多上下文的情况下判断它是好还是坏的编程实践。在两个变量紧密相关的情况下(例如点的x
和y
坐标),使用“链接”赋值将它们设置为某些公共值实际上是完全良好的做法(我甚至会说是“推荐的做法”)。但是,当变量完全不相关时,混合它们在一个单一的“链接”赋值中绝对不是一个好主意。特别是如果这些变量具有不同的类型,这可能会导致意想不到的后果。
volatile
变量,这种区别可能非常重要。 - supercatint main() {
int a, b, c, d;
a = b = c = d = 0;
return a;
}
我有这个汇编代码(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
所以gcc实际上将所有的东西都链接在一起。
sample1 = sample2 = 0;
等于
sample2 = 0;
sample1 = sample2;
sample2 = 0;
sample1 = 0;
sample = UDR = 0;
UDR = 0;
),b)读取输入缓冲区并将数据放入sample
值中(sample = UDR;
)。sample1 = sample2 = 0;
does mean
sample1 = 0;
sample2 = 0;
sample2
被先声明,那么你才能这样做。你不能这样做:int sample1 = sample2 = 0; //sample1 must be declared before assigning 0 to it
正如其他人所说,执行顺序是确定的。= 运算符的优先级保证了从右到左执行。换句话说,它保证了在 sample1 之前给 sample2 赋值。
然而,一行上的多个赋值是不良实践,并被许多编码标准禁止使用(*)。首先,它不太可读(否则你就不会问这个问题了)。其次,它是危险的。例如,如果我们有
sample1 = func() + (sample2 = func());
然后运算符优先级保证了与之前相同的执行顺序(+ 的优先级高于 =,因此需要括号)。sample2 将在 sample1 之前被赋值。但是,与运算符优先级不同,运算符的评估顺序是不确定的,这是未指定的行为。我们无法知道最右边的函数调用是否在最左边的函数调用之前被评估。
编译器可以自由地将上述代码转换为机器码,如下所示:
int tmp1 = func();
int tmp2 = func();
sample2 = tmp2;
sample1 = tmp1 + tmp2;
sample1 = func() + (sample2 = func());
生成三个对 func() 的调用。 - D Krueger处理这个特殊情况... 假设b是一个形式为结构体数组的结构体
{
int foo;
}
假设i是b中的一个偏移量。考虑函数realloc_b(),它返回一个int类型的值并执行数组b的重新分配。考虑以下多重赋值:
a = (b + i)->foo = realloc_b();
根据我的经验,首先解决(b + i),假设它在RAM中为b_i;然后执行realloc_b()。由于realloc_b()会改变RAM中的b,因此导致b_i不再被分配。
变量a被正确赋值,但(b + i)->foo没有被赋值,因为b已经被最左边的赋值项realloc_b()更改了。
这可能会导致段错误,因为b_i可能位于未分配的RAM位置。
为了无错运行,并且使(b + i)->foo等于a,这个单行赋值必须拆分成两个赋值:
a = reallocB();
(b + i)->foo = a;
sample1 = sample2 = 0;
有些编译器会生成汇编代码,与两个赋值语句相比稍微快一些:
sample1 = 0;
sample2 = 0;
特别是当您初始化为非零值时。因为多重赋值会被翻译为:
sample2 = 0;
sample1 = sample2;
因此,您只需进行一次初始化和一次复制,而不是两次初始化。速度提升(如果有的话)将非常微小,但在嵌入式情况下,每一点都很重要!
sample2=0; sample1=sample2;
和 sample1=sample2=0;
生成不同的机器码。 - Lundinsample1=0; sample2=0;
是更快的版本(大约快 1 个 CPU tick...)。 - Lundin