提问人:AlbertStein 提问时间:5/5/2020 最后编辑:Vlad from MoscowAlbertStein 更新时间:5/5/2020 访问量:156
在 C 中,arr[0] = arr[1] = 值是不好的做法吗?
Is bad practice do arr[0] = arr[1] = value in C?
问:
正如我上面所说,这是不好的做法吗?在ASM中,它会是什么样子?我的意思是,我不知道它是否被翻译成这样的东西:
arr[0] = value;
arr[1] = value;
或者像这样:
arr[1] = value;
arr[0] = arr[1];
第二个显然效率更低(imm vs mem)。
提前致谢。
答:
7赞
Vlad from Moscow
5/5/2020
#1
根据 C 语法赋值运算符从右到左计算。
所以这句话
arr[0] = arr[1] = value;
相当于
arr[0] = ( arr[1] = value );
来自 C 标准(6.5.16 赋值运算符)
3 赋值运算符将值存储在由 左操作数。赋值表达式的值为 left 赋值后的操作数,111),但不是左值。的类型 赋值表达式是左操作数后面的类型 左值转换。更新储值的副作用 左操作数在 left 和 右操作数。操作数的评估是未排序的。
因此,根据引文,您可以考虑此声明
arr[0] = arr[1] = value;
喜欢
arr[1] = value;
arr[0] = arr[1];
至于效率,那么编译器可以生成一个高效的目标代码,这与你想象的源代码不同。
0赞
Mickael B.
5/5/2020
#2
如果你想看asm,你可以使用
objdump -d -M intel binary_name
然后,您将搜索该部分,然后搜索函数。.text
main
这是我在计算机上使用的内容和简单易用的变量。int arr[2]
printf
优化输出,编译-O3
mov ecx,0x2a
mov edx,0x2a
未优化
对于此代码:
arr[0] = 42;
arr[1] = 42;
输出为:
mov DWORD PTR [rbp-0x10],0x2a
mov DWORD PTR [rbp-0xc],0x2a
对于此代码:
arr[0] = arr[1] = 42;
输出为:
mov DWORD PTR [rbp-0xc],0x2a
mov eax,DWORD PTR [rbp-0xc]
mov DWORD PTR [rbp-0x10],eax
在第二种情况下,还有一个额外的操作。
因此,对于优化的编译,没有区别,但为了代码的可读性,我不会这样写。
评论
0赞
Russ Schultz
5/5/2020
我很惊讶两者之间存在差异,尤其是在您打开了优化的情况下。
0赞
Mickael B.
5/5/2020
@RussSchultz没有优化时有区别,我已经更新了优化的输出,它是一样的。
0赞
Peter Cordes
5/5/2020
@RussSchultz:从 for locals () 的使用和刚刚存储的值的重新加载可以看出,这是未优化(反优化)的调试模式代码。为什么 clang 在 -O0 时会产生低效的 asm(对于这个简单的浮点求和)?基本上适用于所有编译器。某些编译器甚至可能在调试模式下的那个语句语句中进行了优化,但此编译器没有。优化后的代码完全优化了数组,仅将值具体化为 printf 的寄存器参数。[rbp - ...]
-fno-omit-frame-pointer
a=b=42
0赞
Peter Cordes
5/5/2020
有趣的事实:在这种情况下,保存一些代码大小(2 字节与 5 字节)实际上是一个不错的选择。但是编译器不知道这很慢,并且在一段时间内不会到达它的第 4 个参数 (ECX),而且 1 个周期的依赖性无论如何都是微不足道的。mov ecx,edx
mov r32, imm32
printf
1赞
AlbertStein
5/5/2020
#3
好吧,我查看了汇编代码,得到了这个:
182 Arr[0] = 0x01;
e357: A601 LDA #0x01
e359: C70100 STA 0x0100
184 Arr[0] = Arr[1] = 0x58;
e35d: A658 LDA #0x58
e35f: C70101 STA 0x0101
e362: C70100 STA 0x0100
因此,如果我执行 Arr[0] = 0x58,则预期的结果;并立即 Arr[1] = 0x58;是:
e357: A601 LDA #0x58
e359: C70100 STA 0x0100
e359: C70100 STA 0x0101
(STA: STore 蓄能器 |LDA:LoaD 累加器)
因此,我使用的编译器优化了代码。你们已经说过了,我假设更好的实践(或更好的可读方式)使用:
Arr[0] = 0x58;
Arr[1] = 0x58;
谢谢大家!
评论
0赞
Peter Cordes
5/5/2020
如果您的常量只是一个数字文本,您可能希望通过编写 来避免重复它。否则,是的,为该值重复一些有意义的符号名称通常没问题。为了获得良好的风格,您真正应该避免的唯一一件事是在单独的行上单独声明。那么你当然应该再次使用。Arr[0] = Arr[1] = ...
Arr[1] = Arr[0];
value
评论