4

为什么每次运行应用程序时字符串指针位置都不同,当我使用时,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

4

4 回答 4

13

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

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

编辑:

使用PE.Explorer或类似软件打开编译后的 .exe 文件时,可以看到 UTF-8 编码的“我的字符串”文本。它存在于文件的 .data 部分中,包括一个首选的虚拟地址,该部分应在该部分加载到进程虚拟内存中。

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

于 2015-01-12T19:15:05.300 回答
1

仅仅因为两个字符串相等,并不意味着它们指向相同的引用(我猜这意味着具有相同的指针),C# 不会因为性能考虑而自动对所有字符串进行内部处理等等。如果您希望两个字符串的指针相同,您可以str_02使用string.Intern.

于 2015-01-15T09:59:30.393 回答
1

当我使用fixed时,它将分配内存
,因为 str_01 是常量字符串,它在执行时分配内存并每次都指向相同的位置

fixed (char* pointerToStr_01 = str_01)

但万一

fixed (char* pointerToStr_02 = str_02)

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

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

于 2015-01-20T12:51:22.870 回答
0

我不同意输出

 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;
    }
于 2015-01-15T10:31:18.130 回答