K. *_*los 4 c++ memory-management constants function compiler-optimization
假设你有一个函数
void func(int a, int b, int c, int d);
Run Code Online (Sandbox Code Playgroud)
现在,当你调用这个函数时,因为它有很多参数,而不是像这样调用它:
func(1, 2, 3, 4);
Run Code Online (Sandbox Code Playgroud)
你可以这样称呼它:
const int a = 1;
const int b = 2;
const int c = 3;
const int d = 4;
func(a, b, c, d);
Run Code Online (Sandbox Code Playgroud)
更好地理解每个值是什么。
所以问题是:C++ 编译器只是用第一种方式替换第二种方式,还是实际上为堆栈中的填充变量分配空间,浪费内存和时间?
编译器可以优化 - 并且会尝试使用正确的标志尽可能地优化你的代码。这包括消除你的const ints。这就是原因及其工作原理:
\n\n\n[...]相反,需要一致的实现来模拟(仅)抽象机的可观察行为,如下所述。6 \n[...]
\n6)此规定有时称为 \xe2\x80\x9cas-if\xe2\x80\x9d 规则,因为只要结果就像已遵守该要求,实现就可以自由地忽略本文档的任何要求,从程序的可观察行为可以确定。[...]
\n
或者简单地说:如果你的代码的行为没有改变,编译器可以用它做任何它想做的事情以使其更快。
\n另请参阅:“假设”规则到底是什么?
\nconst int a = 1;\nconst int b = 2;\nconst int c = 3;\nconst int d = 4;\n\nfunc(a, b, c, d);\nRun Code Online (Sandbox Code Playgroud)\n四个变量中的每一个都声明一个对象,并且对象占用内存。\n直觉告诉我们,堆栈需要4 * sizeof(int)更大的字节才能存储所有对象。
然而,我们没有使用任何这些对象的地址,我们只是用它们调用一个函数,所以下面的代码:
\nvoid func(int a, int b, int c, int d);\n\nvoid foo() {\n const int a = 1;\n const int b = 2;\n const int c = 3;\n const int d = 4;\n\n func(a, b, c, d);\n}\nRun Code Online (Sandbox Code Playgroud)\n\nfoo():\n mov ecx, 4\n mov edx, 3\n mov esi, 2\n mov edi, 1\n jmp func(int, int, int, int)\nRun Code Online (Sandbox Code Playgroud)\n注意:如果优化较少或没有优化(例如-O0),您将得到截然不同的程序集,所有四个ints 都驻留在堆栈上。
我们得到的程序集与我们编写的程序相同:
\nfoo():\n mov ecx, 4\n mov edx, 3\n mov esi, 2\n mov edi, 1\n jmp func(int, int, int, int)\nRun Code Online (Sandbox Code Playgroud)\n所以就好像我们从未声明过这些对象并且从未占用内存,而只是使用没有地址的临时对象1, 2, 3。4\n这种优化是允许的,因为可观察到的行为仍然是相同的:我们仍然使用相同的参数进行调用func(由于我们的调用约定,通过寄存器传递)。
一般来说,我建议使用Compiler Explorer来查看编译器生成的程序集类型。\n它可以帮助您了解许多优化(或错过的优化)。
\n