【问题标题】:Can I get a pointer/reference to a constant? C#我可以获得对常量的指针/引用吗? C#
【发布时间】:2021-10-29 21:59:47
【问题描述】:

免责声明:这个问题只是出于好奇,显然人们不应该尝试这样做。

我知道常量不是变量。但是常量的值必须存储在内存中的某个地方,对吗?并且那个内存位置有一个地址。所以一定有办法得到那个地址,对吧?

类似这样的:

const int seven = 7;

void Test()
{
    Console.Write(seven);//7
    int* pointerToSeven = GetThePointerOfConstSeven();//here we get the pointer to the constant
    Increment(pointerToSeven);
    Console.Write(seven);//8
}



void Increment(int* value)
{
    (*value)++;
}

忽略这是一件愚蠢的事情,有没有办法在 C# 中做到这一点?

【问题讨论】:

  • 主要答案是否定的,这是不可能的。这是因为7 不必存储在任何地方的(数据)内存中——它只是在 IL 和机器代码中直接称为数字。但是,const 的一种类型确实需要存储 - const string。然后你可以得到一个char* 并修改字符串。

标签: c# pointers roslyn


【解决方案1】:

主要答案是否定的,这是不可能的。这是因为7 不必存储在任何地方的(数据)内存中——它只是在 IL 和机器代码中直接称为数字。

考虑:

const int seven = 7;
Console.WriteLine(seven);

产生 IL:

IL_0000 ldc.i4.7    
IL_0001 call Console.WriteLine (Int32)

变成机器码:

L0006   mov [rsp+0x20], rax
L000b   mov ecx, 7
L0010   call    System.Console.WriteLine(Int32)

如您所见,const int seven 在代码中变成了文字 7

但是,const 的一种类型确实需要存储 - const string。然后你可以得到一个char*并修改字符串

const string sv = "7";

Console.WriteLine(sv); // outputs 7

unsafe {
    fixed (char* p = sv) {
        *p = '8';
    }
}

Console.WriteLine(sv); // outputs 8

正如您所说,这是一个非常糟糕的主意

【讨论】:

  • 一点点测试表明,至少在调试模式下(非优化),这不会改变 not-yet-Jitted 方法中const 字符串的值,这是一个小提琴dotnetfiddle.net/kX11XS 因为unsafe 而无法运行,你可以复制到 LinqPad 中测试一下。坏主意变得更糟了
  • @查理脸测试,最佳,测试(!)。
  • 是有道理的,因为优化的构建将内联所有内容,因此整个事情都是一次性的。此时,所有引用都指向同一个实例。而如果它还没有被 Jitter,那么看起来 Jitter 无法从实习生池中找到匹配的字符串,并创建一个新的
  • @Charlieface LINQPad 显示 Test 被内联到 MainChangeConst 不是。 (还有一个问题 - 使用带有常量 test 的字符串插值导致编译器创建一个新的常量字符串,其中包含另一个字符串和单词“test”:))
【解决方案2】:

编译器用文字替换常量。在运行时,内存中唯一保存常量值的地方是一个变量,其值是从常量分配的。

顺便说一句,编译器也使用可以在编译时从常量计算的值来执行此操作。这意味着您不会通过为其他常量的简单算术运算定义常量来获得任何效率。例如,定义常量 HALF_PI 和在任何地方都写 Math.PI / 2 之间没有运行时差异。定义HALF_PI 的原因是方便或可读性。

【讨论】:

    猜你喜欢
    • 2019-06-12
    • 2021-12-14
    • 1970-01-01
    • 2012-09-18
    • 2021-03-15
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多