【问题标题】:Is it true that if the address of an uninitialized variable is taken, it is initialized to default value?如果取了一个未初始化变量的地址,是否会被初始化为默认值?
【发布时间】:2020-01-18 15:43:03
【问题描述】:

我有这个代码:

using System;

class Program
{
    unsafe static void f(void* v)
    {}
    static void Main()
    {
        int a;
        unsafe
        {
            f(&a);
        }
        Console.Write(a);
        Console.ReadKey();
    }
}

代码没有错误或异常。代码的输出是0,而a 没有明确给出任何初始值。代码是否正确,编译器是否将 a 隐式初始化为默认值?

【问题讨论】:

标签: c# pointers variables initialization language-lawyer


【解决方案1】:

在不安全的代码中,事情可能会变得奇怪。

首先,让我们看一下 C# 语言规范的Variables 部分。

一个变量必须明确赋值 <...>才能获得它的值。

<...> 变量是初始分配初始未分配。 <...> 一个最初未赋值的变量没有初始值。对于一个最初未分配的变量被认为是在某个位置确定分配的,对该变量的分配必须发生在通向该位置的每个可能的执行路径中。

对于“安全”的 C# 代码也是如此。

在不安全的代码规范中,有一个address-of operator的描述,它告诉我们:

&amp; 运算符不要求其参数被明确赋值,但在&amp; 操作之后,该运算符所应用的变量被认为在操作发生的执行路径中已明确分配。程序员有责任确保在这种情况下确实正确地初始化了变量。

这正是你的情况。您将 address-of 运算符应用于 initially unassigned 变量,然后编译器将其视为 明确分配 变量 - 因此即使在“安全”上下文。

规范告诉我们,程序员负责变量的初始化。如果没有初始化,规范不保证实际变量中会存储什么值。

当前的 C# 编译器为此生成这样的 IL 代码:

.locals init (
    [0] int32 a
)

IL_0000: ldloca.s 0
IL_0002: conv.u
IL_0003: call void Namespace.Program::f(void*)

你看,有一个值类型为int32 的局部变量。 当前的 CLR (.NET Framework) 使用零自动初始化所​​有局部变量 - 这就是为什么变量的初始值为 0,即使它没有在代码中初始化。

我不会依赖这个事实 - AFAIK 无法保证,并且可能会在其他实现中发生变化。

【讨论】:

    猜你喜欢
    • 2010-09-13
    • 1970-01-01
    • 2014-12-29
    • 2021-11-11
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多