【问题标题】:C: Comparison between value initialization during definition & assignment after itC:定义期间的值初始化与之后的赋值之间的比较
【发布时间】:2017-10-05 10:04:50
【问题描述】:

只是出于好奇的问题。在 C 中,我们可以直接初始化值,也可以在定义变量后赋值。喜欢

char* pStr = NULL;

char* pStr;
pStr = NULL;

在功能方面它们是相似的,但编译后有什么不同。后期或现代编译器是否需要额外的指令周期以进行优化。

N.B:我正在审查一个旧代码库,其中第二种情况被广泛使用。这就是为什么我很好奇,如果我可以通过更改所有地方的代码来获得真正的改变。

【问题讨论】:

  • 1.) 没有 C/C++ 语言!您显示的代码发生在两种语言中都有效。 2.) 它们“在各个方面都相似”。第一个是初始化,第二个是赋值。使用局部变量执行此操作并添加 static 存储类修饰符以查看差异。
  • 有一个很棒的工具可以帮助回答这些问题。看看编译器在这里为两者输出了什么:godbolt.org
  • 您在错误的网站上。您要查找的站点是 godbolt,而不是 stackoverflow。
  • 嗯,这里重要的是“定义期间的赋值”不存在。这是初始化,它确实是完全不同的东西。我已经举了一个例子,你可以观察到差异。另一种是尝试分配给一个数组——这是不可能的,尽管你当然可以初始化它。
  • “我正在审查一个旧的代码库......如果我可以通过更改所有地方的代码来获得真正的改变。” -->即使有差异,这肯定是一个微优化 - 一个微小的差异。鉴于它的“旧代码库”可能运行良好,由于错误编辑和代码审查成本等而注入一些功能错误的风险是否值得这个小小的改进?也许是this

标签: c gcc compiler-optimization


【解决方案1】:

第一个 sn-p 用一个值初始化变量。第二个默认初始化它,它对具有自动存储持续时间的指针不做任何事情,然后分配一个值。

对于具有自动存储持续时间的非常量指针,应该没有区别,只是在初始化之前可能会无意中使用它,即UB。

引用或常量等其他内容需要第一种样式。

【讨论】:

    【解决方案2】:

    取决于是本地的还是全局的

    int hello;
    int world=6;
    void fun ( void )
    {
        int foo;
        int bar=5;
        foo=4;
        hello=2;
    }
    

    对于全局变量,hello 将位于 .bss 中(可能需要将引导代码设置为零),并且将创建执行运行时将“变量”设置为 2 的代码。world 将位于 .data 中并具有初始值值 6 在编译时设置。分配的内存/数据空间将具有该值,但可能需要引导程序在使用前放置该数据。

    foo 和 bar 理想地位于堆栈上,这是运行时“分配”,因此无论哪种情况,都需要代码为它们腾出空间,并在运行时将它们设置为一个值。如果您将它们设为静态或基本上是“本地全局变量”,它们现在属于与登陆 .bss 或 .data bar 的全局变量相同的类别,一次初始化为 5,但 foo 在运行时在生成的 .text 代码中设置。

    简单的例子,编译和反汇编将展示所有这些是如何工作的,这不是微不足道的,因为优化器可能会根据其余代码消除您正在寻找的一些内容。 (上面的代码将 hello 设置为 2,foo 和 bar 是死代码,将被优化掉)。

    00000000 <fun>:
       0:   e3a02002    mov r2, #2
       4:   e59f3004    ldr r3, [pc, #4]    ; 10 <fun+0x10>
       8:   e5832000    str r2, [r3]
       c:   e12fff1e    bx  lr
      10:   00000000    andeq   r0, r0, r0
    
    Disassembly of section .data:
    
    00000000 <world>:
       0:   00000006    andeq   r0, r0, r6
    

    如果我做了一个没有启动代码的非常粗略的链接,等等看图片的其余部分:

    00001000 <fun>:
        1000:   e3a02002    mov r2, #2
        1004:   e59f3004    ldr r3, [pc, #4]    ; 1010 <fun+0x10>
        1008:   e5832000    str r2, [r3]
        100c:   e12fff1e    bx  lr
        1010:   00011018    andeq   r1, r1, r8, lsl r0
    
    Disassembly of section .data:
    
    00011014 <__data_start>:
       11014:   00000006    andeq   r0, r0, r6
    
    Disassembly of section .bss:
    
    00011018 <__bss_start>:
       11018:   00000000    andeq   r0, r0, r0
    

    我们看到了 hello 和 world,但是 foo 和 bar 被优化了。

    【讨论】:

    • C++ 的行为相同。编译器当然可以看到,例如,如果您在 main() 中的条目上为 hello 分配了一个值,然后再也没有 hello 在等号的左侧出现,并且只出现在 main() 中,也许它可以在 .data 中分配该值。这将需要一个完整的二进制优化(而不是更典型的每个对象),并且语言可能会干扰该优化。
    猜你喜欢
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多