乘法运算对应的汇编指令有有符号imul和无符号mul两种。由于乘法指令的执行周期较长
,在编译过程中,编译器会先尝试将乘法转换成加法,或使用移位等周期较短的指令。当他们
都不可转换时,才会使用乘法指令。
//C++源码说明
//防止被视为无效代码,将每条运算作为printf参数使用
//printf函数的讲解省略
int nVarOne = argc;
int nVarTwo = argc;
//变量乘常量(常量值为非2的幂)
printf("nVarOne * 15 = %d",nVarOne * 15);
//变量乘常量(常量值为2的幂)
printf("nVarOne * 16 = %d",nVarTwo * 16);
//两常量相乘
printf("2*2 = %d",2*2);
//混合运算
printf("nVarTwo * 4 +5 = %d",nVarTwo *4 + 5);
//两变量相乘
printf("nVarOne * nVarTwo = %d",nVarOne * nVarTwo);
//Debug版本
//C++
printf("nVarOne * 15 = %d",nVarOne * 15);
//反汇编
mov edx,dword ptr [ebp-4]
imul edx,edx,0Fh //有符号数乘法
//printf说明略
//C++
printf("nVarOne * 16 = %d",nVarTwo * 16);
//反汇编
mov eax,dword ptr [ebp-4]
shl eax,4 //利用左移运算符代替乘法运算
//printf说明略
//C++
printf("2*2 = %d",2*2);
//反汇编
编译期间计算2*2,表达式转化为常量
//printf函数
push 4
push offset string "2 * 2 = %d"
call printf
add esp,8
//C++
printf("nVarTwo * 4 +5 = %d",nVarTwo *4 + 5);
//反汇编
mov ecx,dword ptr [ebp-8]
lea edx,[ecx*4+5] //使用lea指令
//printf说明略
//C++
printf("nVarOne * nVarTwo = %d",nVarOne * nVarTwo);
//反汇编
mov ecx,dword ptr [ebp-4]
imul ecx,dword ptr [ebp-8] //直接使用imul
//printf说明略
上面的例子中,乘法运算与加法运算的结合编译器采用LEA指令。此处,lea指令的目的不
是取地址。当这种组合运算中的乘数不等于2,4,8时编译器将采用另一种方式来处理。
//C++
printf("nVarTwo * 9 + 5 = %d",nVarTwo * 9 + 5);
//反汇编
mov eax,dword ptr [ebp-8]
imul eax,eax,9
add eax,5
push eax
push offset string "nVarTwo * 9 + 5 = %d"
call printf
add esp,8
//在开启O2优化的Release版本中,除两个未知变量相乘无法优化,其余形式编译器都可
以优化。
1》nVarOne * 15优化后等价于
tmp = (nVarOne * 2)+nVarOne;
result = (tmp * 4) + tmp;
2》nVarTwo * 16优化同Debug版本
3》2*2优化同Debug版本
4》nVarOne * 4 + 5优化同Debug版本
5》nVarTwo * 9优化后等价于
nVarTwo * 1 + nVarTwo * 8//这样又可以采用lea指令进行运算了。
6》nVarOne * nVarTwo同Debug一样无优化
,在编译过程中,编译器会先尝试将乘法转换成加法,或使用移位等周期较短的指令。当他们
都不可转换时,才会使用乘法指令。
//C++源码说明
//防止被视为无效代码,将每条运算作为printf参数使用
//printf函数的讲解省略
int nVarOne = argc;
int nVarTwo = argc;
//变量乘常量(常量值为非2的幂)
printf("nVarOne * 15 = %d",nVarOne * 15);
//变量乘常量(常量值为2的幂)
printf("nVarOne * 16 = %d",nVarTwo * 16);
//两常量相乘
printf("2*2 = %d",2*2);
//混合运算
printf("nVarTwo * 4 +5 = %d",nVarTwo *4 + 5);
//两变量相乘
printf("nVarOne * nVarTwo = %d",nVarOne * nVarTwo);
//Debug版本
//C++
printf("nVarOne * 15 = %d",nVarOne * 15);
//反汇编
mov edx,dword ptr [ebp-4]
imul edx,edx,0Fh //有符号数乘法
//printf说明略
//C++
printf("nVarOne * 16 = %d",nVarTwo * 16);
//反汇编
mov eax,dword ptr [ebp-4]
shl eax,4 //利用左移运算符代替乘法运算
//printf说明略
//C++
printf("2*2 = %d",2*2);
//反汇编
编译期间计算2*2,表达式转化为常量
//printf函数
push 4
push offset string "2 * 2 = %d"
call printf
add esp,8
//C++
printf("nVarTwo * 4 +5 = %d",nVarTwo *4 + 5);
//反汇编
mov ecx,dword ptr [ebp-8]
lea edx,[ecx*4+5] //使用lea指令
//printf说明略
//C++
printf("nVarOne * nVarTwo = %d",nVarOne * nVarTwo);
//反汇编
mov ecx,dword ptr [ebp-4]
imul ecx,dword ptr [ebp-8] //直接使用imul
//printf说明略
上面的例子中,乘法运算与加法运算的结合编译器采用LEA指令。此处,lea指令的目的不
是取地址。当这种组合运算中的乘数不等于2,4,8时编译器将采用另一种方式来处理。
//C++
printf("nVarTwo * 9 + 5 = %d",nVarTwo * 9 + 5);
//反汇编
mov eax,dword ptr [ebp-8]
imul eax,eax,9
add eax,5
push eax
push offset string "nVarTwo * 9 + 5 = %d"
call printf
add esp,8
//在开启O2优化的Release版本中,除两个未知变量相乘无法优化,其余形式编译器都可
以优化。
1》nVarOne * 15优化后等价于
tmp = (nVarOne * 2)+nVarOne;
result = (tmp * 4) + tmp;
2》nVarTwo * 16优化同Debug版本
3》2*2优化同Debug版本
4》nVarOne * 4 + 5优化同Debug版本
5》nVarTwo * 9优化后等价于
nVarTwo * 1 + nVarTwo * 8//这样又可以采用lea指令进行运算了。
6》nVarOne * nVarTwo同Debug一样无优化