【问题标题】:const vs non-const variable with no change in value once assignconst 与非 const 变量,分配后值没有变化
【发布时间】:2017-11-29 09:54:59
【问题描述】:

在 C++ 中,如果一个变量的值在整个程序中分配后永远不会改变 VS 如果将该变量设为 const ,在这种情况下可执行代码更快? 情况1编译器如何优化可执行代码?

【问题讨论】:

  • 我无法给出明确的答案,这是一个相当广泛的问题。但大多数时候,编译器会以与常量变量类似的方式优化一个只写一次的非全局变量(嗯......显然影响该变量的代码)。
  • const 不是为了让代码更快。这是为了让它更安全。如果变量是const,如果您稍后不小心尝试重新分配它,编译器会警告您,从而避免您自己的错误。
  • 编译器可以轻松查看一个变量是否永远不会被再次分配。如果您将其设为const 并尝试更改该值,编译器会告诉您。所以它知道。
  • @BoPersson 我不确定编译器能否“轻松”分析几百万行代码项目。所以有时,性能方面的 const 关键字会有所帮助,请看下面的示例:stackoverflow.com/a/47550670/7969900

标签: c++ performance constants


【解决方案1】:

聪明的编译器可以理解变量的值永远不会改变,从而优化相关代码,即使程序员没有明确的const关键字。

至于您的第二个问题,当您将变量标记为const 时,可能会发生以下情况:“编译器可以通过不向此变量提供存储来优化此 const,而不是添加它在符号表中。因此,后续读取只需要间接到符号表中,而不是从内存中获取值的指令“。在What kind of optimization does const offer in C/C++? (if any) 阅读更多内容。

我说可能,因为const 并不意味着这肯定是一个常量表达式,可以使用constexpr 来代替,正如我在下面解释的那样。


一般来说,在使用const 关键字时,您应该考虑更安全的代码,而不是更快的代码。因此,除非您为了更安全、更易读的代码而这样做,否则您很可能会成为过早优化的受害者。


奖金:

C++ 提供了constexpr 关键字,它允许程序员将变量标记为标准所称的常量表达式。常量表达式不仅仅是常量。

Difference between `constexpr` and `const`When should you use constexpr capability in C++11? 了解更多信息


PS:Constness 会阻止移动,因此过于随意地使用 const 可能会使您的代码执行速度变慢。

【讨论】:

  • 我会接受过早优化的建议,谢谢
  • 提及constexpr 将是锦上添花。
  • const 对象不必是常量表达式,因此您在第 2 段中提到的优化不必适用。
  • 我不同意过早的优化评论。无论性能提升如何,OP 都应该在适用的情况下使用constconstexpr。在这方面投入的时间使代码更安全、更易读。
  • @gsamaras 不,我的意思是你的第二段。
【解决方案2】:

在什么情况下可执行代码更快?

如果使用const,代码会更快,因为编译器有更多的优化空间。考虑一下这个 sn-p:

int c = 5;
[...]
int x = c + 5;

如果c 是常数,它将简单地将10 分配给x。如果c 不是常量,则取决于编译器是否能够从代码中推断出c 是事实上的常量。

编译器如何优化案例1中的可执行代码?

如果变量不是常数,编译器会更难优化代码。变量的范围越广,编译器就越难以确保变量没有变化。

对于简单的情况,例如局部变量,经过基本优化的编译器将能够推断出该变量是一个常量。所以它会把它当作一个常数来对待。

if (...) {
    int c = 5;
    [...]
    int x = c + 5;
}

对于更广泛的范围,如全局变量、外部变量等,如果编译器无法分析整个范围,它会将其视为普通变量,即分配一些空间、生成加载和存储操作等。

file1.c
int c = 5;

file2.c
extern int c;
[...]
int x = c + 5;

有更积极的优化选项,例如链接时间优化,在这种情况下可能会有所帮助。但是,在性能方面,const 关键字仍然有帮助,尤其是对于具有广泛范围的变量。

编辑:

简单示例

文件 const.C:

const int c = 5;
volatile int x;

int main(int argc, char **argv)
{
        x = c + 5;
}

编译:

$ g++ const.C -O3 -g

反汇编:

5   {
6       x = c + 5;
   0x00000000004003e0 <+0>: movl   $0xa,0x200c4a(%rip)        # 0x601034 <x>
7   }

所以我们只需将 10 (0xa) 移动到 x。

文件 nonconst.C:

int c = 5;
volatile int x;

int main(int argc, char **argv)
{
        x = c + 5;
}

编译:

$ g++ nonconst.C -O3 -g

反汇编:

5   {
6       x = c + 5;
   0x00000000004003e0 <+0>: mov    0x200c4a(%rip),%eax        # 0x601030 <c>
   0x00000000004003e6 <+6>: add    $0x5,%eax
   0x00000000004003e9 <+9>: mov    %eax,0x200c49(%rip)        # 0x601038 <x>
7   }

我们加载c,添加5并存储到x

所以你可以看到,即使有相当激进的优化(-O3)和你能写的最短的程序,const 的效果还是很明显的。

g++ 版本 5.4.1

【讨论】:

  • 现代编译器可以判断何时优化常量,而不管程序员使用constconst 纯粹是为了安全,而不是优化。以 clang 产生的 LLVM IR 为例;你会看到它很乐意抛出你写的所有consts,因为它们对优化器毫无价值,因为C++有mutableconst_cast之类的东西。
  • @JesperJuhl 问题是关于性能和优化,而不是安全性。在某些情况下,IMO 性能方面的 const 会有所帮助。当然, const 是关于安全性的,是的,编译器可以确定何时优化常量。但在某些情况下,编译器很难分析所有代码和变量的使用情况,因此它只是假设变量可能在代码中的某处发生了更改。使用const 编译器可以立即优化常量。
  • 我很确定您完全错了(但很想被证明是错误的)。至少,上次我查看 clang 时,前端刚刚删除了它发送给优化器的 IR 中的所有 const。您能否指出一个具体的、可证明的示例,其中编译器实际上基于 const 优化了 C++?
  • @JesperJuhl 当然,我已经添加了一个示例,请看一下。
  • 谢谢。似乎有种情况,编译器(至少是gcc)实际上会基于const进行优化。我错了。已删除反对票。改为投票。
猜你喜欢
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多