代码之家  ›  专栏  ›  技术社区  ›  Anemoia

C语言中的非初始化变量#

  •  16
  • Anemoia  · 技术社区  · 14 年前

    我有以下代码:

    class Foo
    {
    
        public Foo()
        {
            Bar bar;
            if (null == bar)
            {
    
            }
        }
    }
    
    class Bar { }
    

    代码专家已经看到这会产生一个错误。bar可能未在if语句之前初始化。

    所以现在我想知道:什么是酒吧,不应该是空的吗?它们不是被设置为空的吗?(空指针?)

    8 回复  |  直到 12 年前
        1
  •  34
  •   Jon Skeet    14 年前

    不,局部变量没有默认值 . 他们一定是 明确指定 在你读之前。这减少了你使用变量的机会 认为 你已经给了一个合理的值,实际上它有一些默认值。对于实例或静态变量,这无法完成,因为您不知道将以何种顺序调用方法。

    具体分配详见C 3.0规范第5.3节。

    注意,这与它是引用类型变量无关。这将无法以相同的方式编译:

    int i;
    if (i == 0) // Nope, i isn't definitely assigned
    {
    }
    

    就语言而言,无论如何…显然内存中的存储位置 某物 但这与实现无关。有 通过创建一个具有 out 参数,然后使用IL在方法中查看该参数的值,而不必给它另一个值。CLR根本不介意。那么你就可以 呼叫 这个方法传入了一个没有明确指定的变量,你看,你可以检测到这个值,它很可能就是“全零”值。

    我怀疑cli规范 强制使用具有默认值的局部变量-但我必须检查。除非你在做上述的坏事,否则这对你来说应该无关紧要。

        2
  •  8
  •   Marc Gravell    14 年前

    字段(类/结构上的变量)初始化为 null /零/等。局部变量…好吧-因为(通过“明确的分配”)你不能在没有分配的情况下访问它们没有合理的回答方式;简单地说,它是不可能定义的,因为它是不可能的。我相信他们 发生 成为 无效的 /零/etc(可以通过破解一些 out 代码通过动态IL生成),但这是一个实现细节。


    对于信息,这里有一些crafy代码,显示了一个正式的未初始化变量的值:

    using System;
    using System.Reflection.Emit;
    static class Program
    {
        delegate void Evil<T>(out T value);
        static void Main()
        {
            MakeTheStackFilthy();
            Test();
        }
        static void Test()
        {
            int i;
            DynamicMethod mthd = new DynamicMethod("Evil", null, new Type[] { typeof(int).MakeByRefType()});
            mthd.GetILGenerator().Emit(OpCodes.Ret); // just return; no assignments
            Evil<int> evil = (Evil<int>)mthd.CreateDelegate(typeof(Evil<int>));
            evil(out i);
            Console.WriteLine(i);
        }
        static void MakeTheStackFilthy()
        {
            DateTime foo = new DateTime();
            Bar(ref foo);
            Console.WriteLine(foo);
        }
        static void Bar(ref DateTime foo)
        {
            foo = foo.AddDays(1);
        }
    }
    

    IL 只是 做“ret”-它从不分配任何东西。

        3
  •  2
  •   Justin Niessner    14 年前

    局部变量没有分配默认值。在使用它们之前,必须对它们进行初始化。您可以明确地初始化为 null 虽然:

    public Foo()
    {
        Bar bar = null;
        if (null == bar)
        {
    
        }
    }
    
        4
  •  1
  •   Bryan Denny    14 年前

    局部变量没有分配默认值,甚至没有 null .

        5
  •  1
  •   Henk Holterman    14 年前

    不,局部变量不会自动设置为0(默认值)。

    但因为你(总是)犯了那个错误,这真的没关系。如果它有另一个值,编译器永远不会让你发现。

    不要与字段变量(类成员)混淆,它们 初始化为其类型的默认值(0/null/false/…)。

        6
  •  1
  •   Guffa    14 年前

    价值 bar 未定义。堆栈上为它分配了空间,但空间没有初始化为任何值,因此它包含以前发生在那里的任何内容。

    (但是,局部变量可能被优化为使用寄存器而不是堆栈空间,但它仍然是未定义的。)

    编译器不允许您使用未定义的值,它必须能够在使用变量之前确定该变量已初始化。

    作为比较,vb会初始化局部变量。虽然有时这是可行的,但也可能意味着您在给变量赋予有意义的值之前无意中使用了它,编译器无法确定这是否是您无意中要做的事情。

        7
  •  0
  •   Brian R. Bondy    14 年前

    这无关紧要,因为任何实现c的编译器都不应该编译这类代码。

    如果有默认值,那么它是可编译的。但是没有局部变量。

        8
  •  0
  •   Community Radu Dragan    7 年前

    除了“正确性”之外,局部变量初始化还与CLR的 验证过程 .
    有关详细信息,请参见我对类似问题的回答: Why must local variables have initial values