【问题标题】:Is there any real life example of optimization benefit in case of passing const parameter by value ?在按值传递 const 参数的情况下,是否有任何优化收益的真实例子?
【发布时间】:2014-02-19 00:00:41
【问题描述】:

就是这样,

我尝试调查以下实现功能的一些优点/缺点:

void foo(const int a, const int b)
{
    ...
}

具有通用函数原型,用作API,并包含在头文件中,如下所示:

void foo(int a, int b)

我在以下问题中发现了关于这个主题的大量讨论:

Similar Q

我同意 rlerallut 的回答,他说的是自记录代码以及对代码安全性的角度有点偏执。

但是,这就是问题所在,有人在那里写道,将const 用于传递给函数的常用参数可以带来一些优化好处。我的问题是有人有真实的例子来证明这种说法吗?

【问题讨论】:

  • 你看到这个了吗? stackoverflow.com/questions/6313730/…
  • 这个答案基本上与const 指针有关,我实际上并没有考虑过。我不知道这个答案是否可以应用于按值传递的普通参数。我也发现这个答案有点令人困惑,特别是有一种说法是抛弃 const 指针并在本地范围内修改它的值不是UB,但对全局范围做同样的事情是 UB。有一条评论指出了这种不一致,但我想没有考虑到这一点。
  • 常量值参数的好处是它可以防止编码人员无意中修改它。如果它对优化器有帮助,那将太少注意到,优化器本身只在一种非常特殊类型的代码中帮助你——在你的代码中(而不是在库中)紧密的 CPU 循环,你花费了很大一部分时间。许多人认为这在任何地方都是一件好事,但实际上它只对那些程序计数器喜欢隐藏的小代码壁橱有帮助。它在其余代码中为您所做的就是让调试变得更加困难。
  • 任何“现实生活中的示例”都将特定于特定的编译器,我认为这不是您想要的。一个好的编译器可以自己发现一个参数永远不会被改变和优化,const 与否。在函数参数上使用const 的更好理由是它可以保护您免受某些类型的编程错误。
  • 不,我不认为你应该注意到差异......因为,正如我所说,一个体面的优化器应该能够在没有提示的情况下做正确的事情。

标签: c optimization constants c99


【解决方案1】:

“它可能会帮助编译器优化一些东西(虽然它是一个很长的镜头)。”

我看不出它会有什么不同。在这种情况下,当您尝试修改 const 变量时生成编译器警告/错误是最有用的...

如果您要尝试发明一个实验来比较声明为 const 或未声明为 const 的函数参数以达到优化的目的,请按值传递。这意味着该实验不会修改变量,因为当使用 const 时,您会期望出现警告/错误。一个可能会关心的优化器已经知道在有或没有声明的代码中没有修改变量,然后可以采取相应的行动。该声明有什么关系?如果我发现这样的事情,我会将差异作为错误提交给编译器错误板。

例如,这是我在玩 const vs not 时发现的一个错失机会。

注意 const 与否无关紧要...

void fun0x ( int a, int b);
void fun1x ( const int a, const int b);
int fun0 ( int a, int b )
{
    fun0x(a,b);
    return(a+b);
}
int fun1 ( const int a, const int b )
{
    fun1x(a,b);
    return(a+b);
}

使用 -O2 和 -O3(以及 -O1?)生成的 gcc

00000000 <fun0>:
   0:   e92d4038    push    {r3, r4, r5, lr}
   4:   e1a05000    mov r5, r0
   8:   e1a04001    mov r4, r1
   c:   ebfffffe    bl  0 <fun0x>
  10:   e0850004    add r0, r5, r4
  14:   e8bd4038    pop {r3, r4, r5, lr}
  18:   e12fff1e    bx  lr

0000001c <fun1>:
  1c:   e92d4038    push    {r3, r4, r5, lr}
  20:   e1a05000    mov r5, r0
  24:   e1a04001    mov r4, r1
  28:   ebfffffe    bl  0 <fun1x>
  2c:   e0850004    add r0, r5, r4
  30:   e8bd4038    pop {r3, r4, r5, lr}
  34:   e12fff1e    bx  lr

这可以用更少的周期工作......

push {r4,lr}
add r4,r0,r1
bl fun1x
mov r0,r4
pop {r4,lr}
bx lr

clang/llvm 做了同样的事情,在函数调用后添加燃烧额外的堆栈位置。

谷歌搜索主要展示了关于 const by reference 而不是 const by value 的讨论,然后是 C 和 C++ 关于 const 声明将或不会或不能或不能改变的细微差别等。

如果您在全局变量上使用 const,那么它可以将该项目保留在 .text 中,而不将其保留在 .data 中(并且您的 STM32 微控制器不必将其从闪存复制到 ram)。但这不符合你的规则。优化器可能不在乎,也可能实际上不会接触到它可能知道的变量,将其直接编码到指令中,作为基于指令集的立即数等......尽管非常量会具有相同的条件,但所有事情都保持不变如果不声明为 volatile,同样的好处...

按照您的规则,const 可以避免一些人为错误,如果您尝试将该 const 变量放在等号的左侧,编译器会通知您。

我会认为这违反了您的规则,但是如果在按值传递的函数内部,您做了一些按引用传递的事情并玩了按引用传递 const 与非优化游戏....

【讨论】:

  • 您的句子“在哪里可以使用更少的周期...”之后的代码是铿锵输出吗?
  • 不,那是手工编码的,clang 实际上做了一个堆栈帧,所以它就像 gcc 有更多的指令。
猜你喜欢
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-27
  • 2011-01-03
  • 2021-11-10
  • 2020-01-11
  • 2014-07-24
相关资源
最近更新 更多