gpt4 book ai didi

c# - 不安全的字符串操作会改变不存在的值

转载 作者:太空狗 更新时间:2023-10-29 21:26:06 30 4
gpt4 key购买 nike

C# 中的

string 是一种引用类型,其行为类似于值类型。通常程序员不必担心这一点,因为字符串是不可变的,并且语言设计可以防止我们用它们做无意的危险事情。但是,使用不安全指针逻辑是否可以直接操作字符串的基础值,如下所示:

    class Program
{
static string foo = "FOO";
static string bar = "FOO";
const string constFoo = "FOO";

static unsafe void Main(string[] args)
{
fixed (char* p = foo)
{
for (int i = 0; i < foo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //MMM
Console.WriteLine($"bar = {bar}"); //MMM
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}

运行时,编译器将优化(驻留)字符串,以便 foobar 指向相同的基础值。通过以这种方式操作 foo,我们还更改了 bar 的值。 const 值由编译器内联,不受此影响。到目前为止没有什么奇怪的。

让我们将固定变量从 foo 更改为 constFoo,我们开始看到一些奇怪的行为。

    class Program
{
static string foo = "FOO";
static string bar = "FOO";
const string constFoo = "FOO";

static unsafe void Main(string[] args)
{
fixed (char* p = constFoo)
{
for (int i = 0; i < constFoo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //MMM
Console.WriteLine($"bar = {bar}"); //MMM
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}

尽管我们修复和操作的是 constFoo,但值 foobar 发生了变异。为什么 foobar 发生变异?

如果我们现在更改 foobar 的值,那就更奇怪了。

    class Program
{
static string foo = "BAR";
static string bar = "BAR";
const string constFoo = "FOO";

static unsafe void Main(string[] args)
{
fixed (char* p = constFoo)
{
for (int i = 0; i < constFoo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //BAR
Console.WriteLine($"bar = {bar}"); //BAR
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}

代码运行,我们似乎在某处改变了一些东西,但我们的变量没有变化。 我们在这段代码中改变了什么?

最佳答案

您正在修改驻留字符串表中的字符串,如以下代码所示:

using System;

namespace CoreApp1
{
class Program
{
const string constFoo = "FOO";

static unsafe void Main(string[] args)
{
fixed (char* p = constFoo)
{
for (int i = 0; i < constFoo.Length; i++)
p[i] = 'M';
}

// Madness ensues: The next line prints "MMM":
Console.WriteLine("FOO"); // Prints the interned value of "FOO" which is now "MMM"
}
}
}

这里有一些更难解释的东西:

using System;
using System.Runtime.InteropServices;

namespace CoreApp1
{
class Program
{
const string constFoo = "FOO";

static void Main()
{
char[] chars = new StringToChar {str = constFoo }.chr;

for (int i = 0; i < constFoo.Length; i++)
{
chars[i] = 'M';
Console.WriteLine(chars[i]); // Always prints "M".
}

Console.WriteLine("FOO"); // x86: Prints "MMM". x64: Prints "FOM".
}
}

[StructLayout(LayoutKind.Explicit)]
public struct StringToChar
{
[FieldOffset(0)] public string str;
[FieldOffset(0)] public char[] chr;
}
}

这没有使用任何不安全的代码,但它仍然会改变 intern 表中的字符串。

这里更难解释的是,对于 x86,interned 字符串如您所料更改为“MMM”,但对于 x64,它更改为“FOM”。前两个字符发生了什么变化?我无法解释这一点,但我猜这与将两个字符放入 x64 的单词而不是一个单词有关。

关于c# - 不安全的字符串操作会改变不存在的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57705777/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com