【问题标题】:Does having constant variables as defines make your program smaller?定义常量变量是否会使您的程序更小?
【发布时间】:2015-02-22 23:06:00
【问题描述】:

例子:

#define Var1 35
static const int Var1( 35);

因此,虽然#define 在编译时用35 替换了我使用Var1 的所有地方(如果你有很多编译时间,我认为这会使编译时间稍长一些,因为它会解析代码) ,使用static const int 会使编译器将其视为变量。

这是否意味着当使用static const int 时,它会增加我的程序的内存印记,因为它必须为所有这些常量使用内存,或者编译器是否已经对这种开销进行了优化?

我问的原因是因为我想知道在这样的情况下是否会更好,在调试模式下将它们设置为static const ints(这样你可以在调试时轻松查看值)但让它们#defines 处于发布模式,因此它会使程序更小。

【问题讨论】:

  • 大小差异可以忽略不计,更改发布版本中的整个定义意味着您没有在调试模式下正确测试它(因为代码不一样)。除非您处于非常紧张的内存情况,否则将它们声明为 static const 并忘记与内存问题相关的过早优化,以便节省这么少的钱。 (如果你把它放在一个位置并#include它,你可以在多个地方重复使用相同的 const 声明。)
  • 如果您不能相信编译器能够正确处理此类琐碎的事情,那么您不应该相信它能够正确执行任何操作,而应该使用不同的编译器。如果你觉得你必须对这样的事情进行微观管理,那么某处是非常错误的。
  • 很可能,编译器会为您完成这项工作。 static 东西很容易优化。
  • 优化器可能会将其作为常量传播的一种形式来处理,您可以在类似的问题Do temp variables slow down my program? 中看到,即使变量不是 const,编译器也可以消除它们。像我在回答中那样使用 Godbolt,您可以快速研究简单的示例。

标签: c++ constants c-preprocessor


【解决方案1】:

使用宏来“使程序更小”是不好的,原因如下:

  • 使用宏可能反而会使程序变大,或者没有效果。
  • 宏不遵循 C++ 中的作用域规则。您可能会无意中替换文本。
  • 根据工具的质量,您可能会丢失调试信息。
  • 如果发生有利影响,则效果微乎其微。
  • 避免宏名称冲突的通用约定,即 ALL UPPERCASE,是令人讨厌的。

简而言之,这是一个过早优化的示例。

正如 Donald Knuth 所观察到的,过早的优化是 Evil™。


顺便提一下,static

static const int Var1( 35);
如果在命名空间范围内,

… 是 冗余。默认情况下,命名空间范围常量具有内部链接。随便写

const int Var1 = 35;

... 效果相同,但恕我直言更清楚。

【讨论】:

  • 请问您有一些事实吗?
  • @πάνταῥεῖ:拜托,你能说得更具体点吗?你想要什么事实。统计数据?
  • 我主要挑剔了这一点:“使用宏可能反而会使程序变大......”使用宏很可能会产生相反的效果,IIRC。跨度>
  • @πάνταῥεῖ:关于“使用宏很可能会产生相反的效果”,是的,等等。那是一个论点吗?如果是这样,那么争论是什么(这对我来说没有意义,抱歉)。
  • @πάνταῥεῖ “X 可能发生”并不意味着“不是 X 不能发生”。可能并不意味着必须。你表面上的不同意实际上是不同意的。
【解决方案2】:

如果是static,那么编译器可以看到它只在该翻译单元内部使用,而不必怀疑它是如何在外部使用的,这是一个优势。如果您不做任何事情使其必须成为实际变量(例如创建指向它的指针),那么编译器通常会对其进行优化。

更友好的方法可能是使用枚举

enum { Var1 = 35 };

或者在 C++11 中,constexpr

constexpr int Var1 = 35;

如果你以后有的话,这些还有一个好处是不会在另一个范围内弄乱同名变量

void f() {
    int Var1;
}

#define 会将其变成int 35;

但是使用的内存差异会非常小,可能非常微不足道,除非您处于极其有限的环境中,否则永远不会对性能产生任何可衡量的影响。

【讨论】:

  • 嗯,我发现第一段的论点很可疑。我认为您应该详细说明想象的优势。关于枚举,当常量是类成员(避免需要提供类外定义)时,非常适合与 C++03 兼容的代码。对于简单的int 命名空间范围常量,constexpr 完全是多余的。它已经尽可能地保持不变,一个编译时间常数。
  • @Cheersandhth.-如果您对冗余命名空间范围是正确的。我没有意识到它会因为它是 constexpr 而具有静态链接。至于第一部分,优势就是OP想要的,即不让静态变量占用内存。如果有很多,那么优势实际上可能很明显
【解决方案3】:

“这是否意味着当使用 static const int 时它会增加我的程序的内存印记,因为它必须为所有这些常量使用内存,或者编译器是否已经优化了这种开销? "

这完全取决于您的实际编译器的实现,以及优化功能的性能。

对于简单的数字常量,在逻辑上下文中我更喜欢使用enum 声明。
大多数时候我发现使用static const int Var1( 35); 是比#define'd 值更好的选择,因为我可以完全控制应该看到的范围。

【讨论】:

    【解决方案4】:

    每个体面的编译器都会进行常量传播以查看哪个表达式将保持不变。 const 帮助编译器完成这项工作。

    大多数编译器做得很好的下一件事是删除代码中未使用的部分。这就是为什么 const 外部不可见的变量既不直接(局部变量,静态变量)也不间接(即变量的地址未被用作为指针赋值的引用)被优化器。

    例子:

    static const int e = 29;
    int main() 
    {
        int x = e; 
        return x + 1; 
    }
    

    将由 MSVC 2013 在发布模式下编译为:

    PUBLIC  _main
    _TEXT   SEGMENT
    _main   PROC                        
        mov eax, 30                 ; optimized the code to return 30
        ret 0
    _main   ENDP
    _TEXT   ENDS
    END                             ;  no place is reserved nowhere for the static.  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-25
      • 1970-01-01
      • 2015-12-27
      • 1970-01-01
      • 1970-01-01
      • 2015-08-03
      • 1970-01-01
      相关资源
      最近更新 更多