C++ 如何避免指针运算中的乘法?

C++ 如何避免指针运算中的乘法?,c++,visual-c++,code-generation,multiplication,pointer-arithmetic,C++,Visual C++,Code Generation,Multiplication,Pointer Arithmetic,如果我写 int main(int argc, char *argv[]) { int temp[50][3]; return &temp[argc] - &temp[0]; } 并用VisualC++编写,返回: 009360D0 55 push ebp 009360D1 8B EC mov ebp,esp 009360D3 8B 45 08

如果我写

int main(int argc, char *argv[])
{
    int temp[50][3];
    return &temp[argc] - &temp[0];
}

并用VisualC++编写,返回:

009360D0 55                   push        ebp  
009360D1 8B EC                mov         ebp,esp  
009360D3 8B 45 08             mov         eax,dword ptr [argc]  
009360D6 8D 0C 40             lea         ecx,[eax+eax*2]  
009360D9 B8 AB AA AA 2A       mov         eax,2AAAAAABh  
009360DE C1 E1 02             shl         ecx,2  
009360E1 F7 E9                imul        ecx  
009360E3 D1 FA                sar         edx,1  
009360E5 8B C2                mov         eax,edx  
009360E7 C1 E8 1F             shr         eax,1Fh  
009360EA 03 C2                add         eax,edx  
009360EC 5D                   pop         ebp  
009360ED C3                   ret  
为什么我在这里得到的是
imul
指令而不是位移位等。?我觉得这很烦人,因为我在一个紧密的循环中做这样的指针运算,我怀疑
imul
正在破坏它的性能。无论如何,这是不必要的

有没有一个好的方法来防止它,而代之以更便宜的操作

更新: 在我的原始程序中,我尝试添加一个伪变量,使每个元素的大小为4的倍数,而不是3的倍数,这样编译器就可以使用位移位而不是除法

结果如何?即使数据结构更大,程序的运行时间也从9.2秒减少到7.4秒

所以是的,这确实非常缓慢

为什么我在这里得到的是
imul
指令而不是位移位等

乘法是除以3(每个内部数组的大小),使用
0x2aaaaab
是231/3的事实。你不能用少量的移位和加法来做到这一点;乘法确实是最快的选择

我怀疑imul正在扼杀它的性能

在大多数现代平台上,整数乘法通常与更简单的运算一样快,因此它可能是最快的选择,即使它可以被几个移位和加法所取代。当您遇到性能问题时,始终进行测量以找到真正的瓶颈;它们经常在你最不怀疑的地方

有没有一个好的方法来防止它,而代之以更便宜的操作


在乘法运算非常昂贵的平台上:避免使用大小笨拙的数据结构数组;并避免减去指针,因为这需要除以对象大小。

您是否尝试过用位移位替换mul指令并对结果进行基准测试?@larsmans:没有,因为我使用的是向量迭代器(下面是指针),因此我不必取消对它们的引用以获取原始指针。如果我这样做了,我可能会意外地取消对结束迭代器的引用,导致未定义的行为。(检查结束迭代器本身是否有过多的指令)嗯,优化级别是多少?但是,如果不能保证输入是一个向量迭代器,那么“将是指针”的假设就相当大胆了。“我怀疑imul正在破坏它的性能”。。。你最好检查一下这个。您的编译器在这方面几乎总是正确的。我只想指出,即使在x86上,这也确实会降低性能(请参阅我的更新)。所以你的最后一段写得很对,谢谢。整数乘法很快(
imuleax,ecx
是英特尔自Nehalem以来的3c延迟/1c吞吐量,AMD自Ryzen以来的3c延迟/1c吞吐量),但整数
add
更快:1c延迟/0.25c吞吐量(英特尔自Haswell以来)。对于可以自动矢量化的代码,SIMD integer add也比SIMD integer乘法便宜得多,比如10c与1c延迟。(与标量整数的吞吐量差异类似)。看见但是是的,
imul
比多个移位/加法好,并且是一个单uop(或者对于产生像这里这样的高一半结果的版本是一对uop)。gcc和clang都使用最多2 LEA或其他指令乘以小常数或2的幂,但是使用
imul
而不是其他3条指令。