65,209
社区成员
发帖
与我相关
我的任务
分享
理解和讨论之前请先学会如何观察!
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……
对学习编程者的忠告:
多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
无profiler不要谈效率!!尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代!
#include <cstdlib>
#include <cstdio>
int test()
{
return rand();
}
int main(int, const char **)
{
int n = 0;
for (size_t i = 0; i < 10000000; i++)
{
n ^= test();
}
printf("%d\n", n);
for (size_t i = 0; i < 10000000; i++)
{
auto f = []()->int {return rand(); };
n ^= f();
}
printf("%d\n", n);
return 0;
}
$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00000000004004b0 <main>:
4004b0: 55 push %rbp
4004b1: 53 push %rbx
4004b2: bd 80 96 98 00 mov $0x989680,%ebp
4004b7: 31 db xor %ebx,%ebx
4004b9: 48 83 ec 08 sub $0x8,%rsp
4004bd: 0f 1f 00 nopl (%rax)
4004c0: e8 db ff ff ff callq 4004a0 <rand@plt>
4004c5: 31 c3 xor %eax,%ebx
4004c7: 48 83 ed 01 sub $0x1,%rbp
4004cb: 75 f3 jne 4004c0 <main+0x10>
4004cd: 89 da mov %ebx,%edx
4004cf: be b4 06 40 00 mov $0x4006b4,%esi
4004d4: bf 01 00 00 00 mov $0x1,%edi
4004d9: 31 c0 xor %eax,%eax
4004db: bd 80 96 98 00 mov $0x989680,%ebp
4004e0: e8 ab ff ff ff callq 400490 <__printf_chk@plt>
4004e5: 0f 1f 00 nopl (%rax)
4004e8: e8 b3 ff ff ff callq 4004a0 <rand@plt>
4004ed: 31 c3 xor %eax,%ebx
4004ef: 48 83 ed 01 sub $0x1,%rbp
4004f3: 75 f3 jne 4004e8 <main+0x38>
4004f5: 89 da mov %ebx,%edx
4004f7: be b4 06 40 00 mov $0x4006b4,%esi
4004fc: bf 01 00 00 00 mov $0x1,%edi
400501: 31 c0 xor %eax,%eax
400503: e8 88 ff ff ff callq 400490 <__printf_chk@plt>
400508: 48 83 c4 08 add $0x8,%rsp
40050c: 31 c0 xor %eax,%eax
40050e: 5b pop %rbx
40050f: 5d pop %rbp
400510: c3 retq
两个循环体是一样的 callq (rand), xor, sub, jne 。
4004c0 - 4004cb
4004e8 - 4004f3; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.23026.0
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC ?test@@YAMXZ ; test
PUBLIC main
PUBLIC __real@444a4c29
EXTRN _fltused:DWORD
pdata SEGMENT
$pdata$main DD imagerel $LN9
DD imagerel $LN9+128
DD imagerel $unwind$main
pdata ENDS
; COMDAT __real@444a4c29
CONST SEGMENT
__real@444a4c29 DD 0444a4c29r ; 809.19
CONST ENDS
xdata SEGMENT
$unwind$main DD 020e01H
DD 0700a720eH
xdata ENDS
; Function compile flags: /Odtp
; COMDAT ??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ
_TEXT SEGMENT
this$ = 8
??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ PROC ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator(), COMDAT
; 15 : auto f = []()->float {return 333 * 2.43; };
mov QWORD PTR [rsp+8], rcx
movss xmm0, DWORD PTR __real@444a4c29
ret 0
??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ ENDP ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator()
_TEXT ENDS
; Function compile flags: /Odtp
_TEXT SEGMENT
$T1 = 32
f$2 = 33
i$3 = 40
i$4 = 48
__formal$ = 80
__formal$ = 88
main PROC
; 7 : {
$LN9:
mov QWORD PTR [rsp+16], rdx
mov DWORD PTR [rsp+8], ecx
push rdi
sub rsp, 64 ; 00000040H
; 8 : for (size_t i = 0; i < 10000000; i++)
mov QWORD PTR i$3[rsp], 0
jmp SHORT $LN4@main
$LN2@main:
mov rax, QWORD PTR i$3[rsp]
inc rax
mov QWORD PTR i$3[rsp], rax
$LN4@main:
cmp QWORD PTR i$3[rsp], 10000000 ; 00989680H
jae SHORT $LN3@main
; 9 : {
; 10 : test();
call ?test@@YAMXZ ; test
; 11 : }
jmp SHORT $LN2@main
$LN3@main:
; 12 :
; 13 : for (size_t i = 0; i < 10000000; i++)
mov QWORD PTR i$4[rsp], 0
jmp SHORT $LN7@main
$LN5@main:
mov rax, QWORD PTR i$4[rsp]
inc rax
mov QWORD PTR i$4[rsp], rax
$LN7@main:
cmp QWORD PTR i$4[rsp], 10000000 ; 00989680H
jae SHORT $LN6@main
; 14 : {
; 15 : auto f = []()->float {return 333 * 2.43; };
lea rax, QWORD PTR $T1[rsp]
mov rdi, rax
xor eax, eax
mov ecx, 1
rep stosb
; 16 : f();
lea rcx, QWORD PTR f$2[rsp]
call ??R<lambda_a063bd16e7642c22fd3d9fd00722fd02>@@QEBAMXZ ; <lambda_a063bd16e7642c22fd3d9fd00722fd02>::operator()
; 17 : }
jmp SHORT $LN5@main
$LN6@main:
; 18 : return 0;
xor eax, eax
; 19 : }
add rsp, 64 ; 00000040H
pop rdi
ret 0
main ENDP
_TEXT ENDS
; Function compile flags: /Odtp
_TEXT SEGMENT
?test@@YAMXZ PROC ; test
; 4 : return 333 * 2.43;
movss xmm0, DWORD PTR __real@444a4c29
; 5 : }
ret 0
?test@@YAMXZ ENDP ; test
_TEXT ENDS
END
上个没优化的
$ cat test.cpp
#include <cstdlib>
float test()
{
return 333 * 2.43;
}
int main(int, const char **)
{
for (size_t i = 0; i < 10000000; i++)
{
test();
}
for (size_t i = 0; i < 10000000; i++)
{
auto f = []()->float {return 333 * 2.43; };
f();
}
return 0;
}
$ g++ --std=c++11 --pedantic -g -O2 test.cpp
$ g++ --version
g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ objdump -d a.out > a.ss
a.ss
0000000000400400 <main>:
400400: 31 c0 xor %eax,%eax
400402: c3 retq
优化之后 main 只剩了一句 return 0;