为什么字符串指针位置不同

本文关键字:位置 指针 字符串 为什么 | 更新日期: 2023-09-27 18:36:33

为什么每次运行应用程序时字符串指针位置不同,当我使用StringBuilder时,但当我声明变量时相同?

void Main()
{
    string str_01 = "my string";
    string str_02 = GetString();
    unsafe 
    {
        fixed (char* pointerToStr_01 = str_01)
        {
            fixed (char* pointerToStr_02 = str_02)
            {
                Console.WriteLine((Int64)pointerToStr_01);
                Console.WriteLine((Int64)pointerToStr_02);
            }
        }
    }
}
private string GetString()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("my string");
    return sb.ToString();
}

输出:

40907812 178488268

下次:

40907812 179023248

下次:

40907812 178448964

为什么字符串指针位置不同

str_01包含对常量字符串的引用。 但是,StringBuilder动态生成字符串实例,因此返回的字符串实例与具有相同内容的常量字符串在引用上不是同一实例。 System.Object.ReferenceEquals()会返回false.

由于str_01是对常量字符串的引用,因此其数据可能存储在可执行文件的数据部分中,该部分始终在应用程序虚拟地址空间中获取相同的地址。

编辑:

使用 PE 打开已编译的.exe文件时,可以看到 UTF-8 编码的"my string"文本。资源管理器或类似软件。它存在于文件的 .data 部分中,包括首选虚拟地址,该部分应加载到进程虚拟内存中。

但是,我无法重现str_01在多次运行应用程序时具有相同的地址,可能是因为我的 x64 Windows 8.1 执行地址空间布局随机化 (ASLR)。因此,在应用程序的多次运行中,所有指针都将不同,即使是那些直接指向加载的 PE 部分的指针也是如此。

仅仅因为两个字符串相等并不意味着它们指向相同的引用(我想这意味着具有相同的指针),C# 不会自动插入所有字符串,因为性能考虑等等。如果您希望两个字符串的指针相同,您可以使用 string.Intern 实习str_02

当我使用固定时,它会分配一个内存
由于str_01是常量字符串,因此它在执行时分配内存并每次都
指向同一位置

fixed (char* pointerToStr_01 = str_01)

但在以下
情况下

fixed (char* pointerToStr_02 = str_02)

它动态分配内存,因此指向位置每次都不同

因此,每次运行时字符串指针都有差异

我不同意输出

 Console.WriteLine((Int64)pointerToStr_01);

对你来说总是一样,因为我亲自测试了它,以使我的观点更清楚。

让我们看一下这两种情况:

  • 在字符串 str_01 = "my string" 的情况下,当您打印此变量的指针值时,它将与以前不同,因为每次创建新的 String 对象(即字符串是不可变的)并且"我的字符串"被分配给它。然后在 Fixed 语句中,您正在打印指针的值,当您再次执行程序时,该值超出了范围,并且不会记住以前的值。
  • 我认为,到目前为止,您可以自我解释StringBuilder的行为。

另请与以下人员联系:

 string str_01 = GetString();
 private static string GetString()
    {
        var sb = new String(new char[] {'m','y',' ','s','t','r','i','n','g'});
        return sb;
    }