【问题标题】:Initializing variables in C在 C 中初始化变量
【发布时间】:2011-11-02 01:57:37
【问题描述】:

我知道,有时如果你不初始化int,如果你打印整数,你会得到一个随机数。

但是将所有内容初始化为零似乎有点愚蠢。

我问是因为我正在评论我的 C 项目,而且我对缩进非常直接,它可以完全编译(90/90,谢谢 Stackoverflow),但我希望在样式点上获得 10/10。

那么问题来了:什么时候适合初始化,什么时候应该声明一个变量:

int a = 0;

对比

int a;

【问题讨论】:

    标签: c initialization


    【解决方案1】:

    在以下几种情况下,您不应该初始化变量:

    1. 当它具有静态存储持续时间(static 关键字或全局变量)并且您希望初始值为零时。如果您显式初始化,大多数编译器实际上会将零存储在二进制文件中,这通常只是浪费空间(对于大型数组来说可能是巨大的浪费)。
    2. 当您将立即将变量的地址传递给另一个填充其值的函数时。在这里,初始化只是浪费时间,可能会让代码读者感到困惑,他们想知道为什么要将某些内容存储在即将被覆盖的变量中。
    3. 在后续代码完成执行之前无法确定变量的有意义值时。在这种情况下,使用诸如零/NULL 之类的虚拟值初始化变量是非常有害的,因为如果您有一些从未分配过有意义值的代码路径,这会防止编译器警告您。编译器擅长警告您访问未初始化的变量,但不能警告您“仍然包含虚拟值”变量。

    除了这些问题之外,我认为在可能的情况下初始化非静态变量通常是一种好习惯。

    【讨论】:

    • +1 我同意您的回答,并且发现自己对大多数其他答案感到非常惊讶。 (这些天他们在学校教他们什么?)但是我对你的“巨大浪费”有一个小小的狡辩:在过去初始化.bss 只是大约三行汇编代码(并且问题被标记为@ 987654324@).
    • “巨大浪费”是指全零对象存储在数据而不是 bss 中。大多数(所有?)编译器在您显式初始化时都会这样做,这就是为什么我建议尽可能使用隐式零初始化。
    • 我回想起 80 年代中期基于 ROM 系统的 crt0。但是现在操作系统显然使用了按需零填充;见this。快速测试echo 'char foo[0x88888]; int main(void) {return 0;}' | gcc -x c - && readelf -a a.out | grep bss 给出... .bss NOBITS ... 0888a8 ...
    • +1 表示深思熟虑的合理回复。这可以很好地了解变量未初始化的原因。但是,我来自相反的阵营。我总是被告知,必须初始化所有变量以避免偶尔使用随机值(以及因此,不可重现的错误)。我想给出第三个反例案例:不幸的是,最近我经常使用代码,其作者并不关心警告。所以我有数百个。因此,我不能依赖编译器警告。在这种情况下,我更喜欢确定性行为而不是另一个警告
    • 我相信代码的简洁性和可读性经常被低估。在代码维护中以更高的错误倾向为代价节省一个单词写入(如果以后有人会使用该变量怎么办?他/她会启用编译器警告吗?如果应该更新值的函数没有触及它怎么办,例如因为错误?)对我来说看起来有点疯狂。我希望这种优化只在软件解码器等性能关键部分执行,其他任何地方都没有。 (顺便说一句,如果代码路径中有另一个,许多编译器甚至会跳过该写入)
    【解决方案2】:

    还没有提到的一条规则是:当变量在函数内声明时,它不会被初始化,而当它在静态或全局范围内声明时,它被设置为 0:

    int a; // is set to 0
    
    void foo() {
      int b;  // set to whatever happens to be in memory there
    }
    

    但是 - 为了便于阅读,我通常会在声明时初始化所有内容。

    如果你有兴趣详细了解这类东西,我推荐this presentationthis book

    【讨论】:

      【解决方案3】:

      我能想到几个原因:

      1. 当您稍后将在代码中对其进行初始化时。

        int x;
        
        if(condition)
        {
            func();
            x = 2;
        }
        else
        {
           x = 3;
        }
        anotherFunc(x); // x will have been set a value no matter what
        
      2. 当您需要一些内存来存储由函数或另一段代码设置的值时:

        int x;  // Would be pointless to give x a value here
        scanf("%d", &x);
        

      【讨论】:

      • 该代码将在 g++ 中生成警告,因为 x 在未初始化的情况下使用。
      【解决方案4】:

      如果变量在函数的范围内而不是类的成员,我总是初始化它,否则你会收到警告。即使稍后将使用此变量,我也更喜欢在声明时分配它。

      对于成员变量,你应该在你的类的构造函数中初始化它们。

      对于指针,总是将它们初始化为一些默认值,尤其是 NULL,即使它们以后要使用,但在未初始化时它们是危险的。

      此外,建议使用编译器支持的最高级别警告来构建代码,这有助于识别不良做法和潜在错误。

      【讨论】:

      • 谢谢,我在终端上的 gcc/Linux shell 上编程(对不起,如果这些是错误的词,我只是输入代码并希望最好),我们被告知使用 gcc -Wall 编译-Werror -ansi -pedantic-errors xxx.c main.c 所以它告诉你最愚蠢的小东西是错误,所以谢谢你的提示!
      【解决方案5】:

      静态和全局变量将为您初始化为零,因此您可以跳过初始化。自动变量(例如在函数体中定义的非静态变量)可能包含垃圾,并且应该总是被初始化。

      如果您在初始化时需要一个非零的特定值,那么您应该始终显式初始化。

      【讨论】:

        【解决方案6】:

        初始化变量总是好的做法,但有时它不是严格必要的。考虑以下几点:

        int a;
        for (a = 0; a < 10; a++) { } // a is initialized later
        

        void myfunc(int& num) {
          num = 10;
        }
        
        int a;
        myfunc(&a); // myfunc sets, but does not read, the value in a
        

        char a;
        cin >> a; // perhaps the most common example in code of where
                  // initialization isn't strictly necessary
        

        这些只是一些示例,其中不必严格初始化变量,因为它是稍后设置的(但不会在声明和初始化之间访问)。

        一般来说,总是在声明时初始化变量并没有什么坏处(事实上,这可能是最佳实践)。

        【讨论】:

          【解决方案7】:

          一般来说,不需要初始化变量,但有 2 个值得注意的例外:

          1. 您正在声明一个指针(而不是立即分配它) - 您 应始终将这些设置为 NULL 作为良好的风格和防御性 编程。
          2. 如果在声明变量时,您已经知道 将为其分配什么值。进一步的任务用完 更多 CPU 周期。

          除此之外,还要让变量进入您希望它们处于您将要执行的操作的正确状态。如果您不打算在操作更改其值之前读取它们(并且该操作不关心它处于什么状态),则无需初始化它们。

          就我个人而言,无论如何我总是喜欢初始化它们;如果您忘记为其分配一个值,并且错误地将其传递给函数(如剩余缓冲区长度),通常会干净地处理 0 - 32532556 不会。

          【讨论】:

          • 所以你建议他只有在两种情况下才有必要,然后说你总是这样做并举例说明为什么他应该这样做?
          • 感谢 septical,我喜欢“除此之外,这是关于让变量进入您希望它们处于您将要执行的操作的正确状态。”很有见地
          • 我从来没有说过这只是必要的,只是在 90% 的情况下没有人会注意到差异。在示例中,应用程序仍然会被破坏——只有在没有初始化的情况下,您可能会崩溃而不是提供不正确的结果。好的风格要求你应该初始化它们(没有什么要求你应该),所以这就是我提供我的意见的原因。
          【解决方案8】:

          绝对没有理由不初始化变量,如果变量被分配两次,编译器足够聪明,可以忽略第一次分配。当您认为理所当然的事情(例如在使用之前分配变量)不再正确时,代码很容易增长。考虑:

          int MyVariable;
          void Simplistic(int aArg){
              MyVariable=aArg;
          }
          
          //Months later:
          
          int MyVariable;
          void Simplistic(int aArg){
              MyVariable+=aArg; // Unsafe, since MyVariable was never initialized.
          }
          

          一个很好,另一个让你陷入困境。有时您会遇到应用程序在调试模式下运行的问题,但发布模式会引发异常,原因之一是使用了未初始化的变量。

          【讨论】:

          • simplistic 的第一个版本是安全的。第二个版本不是,因为它增加了 MyVariable 的现有值。 MyVariable 从未初始化,因此我们将 aArg 添加到某个未知值。
          • MyVariable 具有静态存储持续时间,因此不可能未初始化。如果没有显式初始化,则其初始值为零。
          【解决方案9】:

          只要我在写入变量之前没有读取它,我就不必费心初始化它。

          先读后写会导致严重且难以发现的错误。我认为这类 bug 臭名昭著,足以在流行的 SICP 讲座视频中提及。

          【讨论】:

          • 这意味着在打印语句中使用变量,将其用作表达式的一部分,其结果取决于变量的值等。并且,写入变量意味着,为其赋值。
          【解决方案10】:

          初始化变量,即使不是严格要求,也始终是一个好习惯。在开发过程中输入的几个额外字符(如“= 0”)可能会在以后节省数小时的调试时间,尤其是当忘记某些变量仍未初始化时。

          顺便说一句,我觉得声明一个接近其用途的变量

          以下是不好的:

          int a;    // line 30
          ...
          a = 0;    // line 40
          

          以下是好的:

          int a = 0;  // line 40
          

          另外,如果要在初始化后立即覆盖变量,例如

          int a = 0;
          a = foo();
          

          最好写成

          int a = foo();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-11
            • 2015-04-22
            • 1970-01-01
            • 2017-11-30
            相关资源
            最近更新 更多