首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果对变量进行初始化,编译器的性能会受到什么影响?

如果对变量进行初始化,编译器的性能会受到什么影响?
EN

Stack Overflow用户
提问于 2012-09-27 01:14:35
回答 4查看 968关注 0票数 1

萨特说:

在C和C++的低效率传统中,编译器通常不需要初始化变量,除非您显式地初始化它(例如,局部变量,被遗忘的成员从构造函数初始化程序列表中省略)

我一直在想,为什么编译器不初始化原语,比如int32,然后浮动到0。如果编译器初始化它,性能会受到什么影响?它应该比不正确的代码更好。

EN

回答 4

Stack Overflow用户

发布于 2012-09-27 08:24:47

事实上,这个论点是不完整的。统一变量可能有两个原因:效率和缺乏合适的缺省值。

1)效率

大多数情况下,C编译器只是汇编翻译程序的C,而没有进行任何优化。

如今,我们有了智能编译器和消除死商店,在大多数情况下,这将消除冗余存储。演示:

代码语言:javascript
复制
int foo(int a) {
    int r = 0;
    r = a + 3;
    return r;
}

转化为:

代码语言:javascript
复制
define i32 @foo(i32 %a) nounwind uwtable readnone {
  %1 = add nsw i32 %a, 3
  ret i32 %1
}

不过,在某些情况下,即使是更聪明的编译器也无法消除冗余存储,这可能会产生影响。对于后来被分段初始化的大型数组..。编译器可能没有意识到所有的值最终都会被初始化,因此不会删除冗余的写操作:

代码语言:javascript
复制
int foo(int a) {
    int* r = new int[10]();
    for (unsigned i = 0; i <= a; ++i) {
        r[i] = i;
    }
    return r[a % 2];
}

注意以下对memset的调用(我需要用()作为new调用的后缀,这是值初始化)。即使0是不需要的,它也没有被消除。

代码语言:javascript
复制
define i32 @_Z3fooi(i32 %a) uwtable {
  %1 = tail call noalias i8* @_Znam(i64 40)
  %2 = bitcast i8* %1 to i32*
  tail call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 40, i32 4, i1 false)
  br label %3

; <label>:3                                       ; preds = %3, %0
  %i.01 = phi i32 [ 0, %0 ], [ %6, %3 ]
  %4 = zext i32 %i.01 to i64
  %5 = getelementptr inbounds i32* %2, i64 %4
  store i32 %i.01, i32* %5, align 4, !tbaa !0
  %6 = add i32 %i.01, 1
  %7 = icmp ugt i32 %6, %a
  br i1 %7, label %8, label %3

; <label>:8                                       ; preds = %3
  %9 = srem i32 %a, 2
  %10 = sext i32 %9 to i64
  %11 = getelementptr inbounds i32* %2, i64 %10
  %12 = load i32* %11, align 4, !tbaa !0
  ret i32 %12
}

2)违约?

另一个问题是缺乏合适的价值。虽然float完全可以初始化为NaN,但整数又如何呢?没有一个整数值表示没有值,根本没有!0是一个候选值(包括其他的),但是有人可能会说它是最糟糕的候选值之一:它是一个非常可能的数字,因此可能对手头的usecase有一个特定的含义;您确定这个意思是默认的吗?

思想食粮

最后,统一变量有一个很好的优点:它们是可检测的。编译器可能会发出警告(如果它足够聪明的话),而引发错误。这使得的逻辑问题可以检测到,并且只有检测到的内容才能被纠正。

当然,哨兵值(如NaN )也同样有用。不幸的是。整数没有。

票数 3
EN

Stack Overflow用户

发布于 2012-09-27 01:38:09

初始化可能会影响性能的方式有两种。

首先,初始化变量需要时间。当然,对于单个变量,它可能可以忽略不计,但正如其他人所建议的,它可以与大量的变量、数组等一起使用。

第二,谁说零是合理的违约?对于每一个对零是有用的缺省值的变量,可能还有另一个不适用的变量。在这种情况下,如果你真的初始化为零,那么你将这个变量重新初始化为你想要的任何值,就会招致更多的开销。实际上,您需要支付两次初始化开销,而不是在未发生默认初始化时支付一次。请注意,无论您选择什么作为默认值,零或其他值,这都是正确的。

考虑到开销的存在,不初始化和让编译器捕获对未初始化变量的引用通常更有效。

票数 2
EN

Stack Overflow用户

发布于 2012-09-27 01:26:34

基本上,变量引用内存中可以修改以保存数据的位置。对于一个统一的变量,程序所需要知道的就是这个位置,编译器通常会提前找出这一点,所以不需要指令。但是,当您希望初始化它(也就是说,0)时,程序需要使用额外的指令来实现。

一种想法可能是,在程序启动时,使用memset将整个堆清零,然后初始化所有静态内容,但在读取之前不需要对任何动态设置的堆进行初始化。对于基于堆栈的函数来说,这也是一个问题,每次调用函数时,都需要将它们的堆栈帧归零。简而言之,允许变量默认为未定义更有效,特别是当堆栈经常被新调用的函数覆盖时。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12612707

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档