Поврежденная строка в C #

Я столкнулся с «CorruptedString» (решение) . Вот следующий код программы из книги:

var s = "Hello";
string.Intern(s);
unsafe
{
  fixed (char* c = s)
    for (int i = 0; i < s.Length; i++)
      c[i] = 'a';
}
Console.WriteLine("Hello"); // Displays: "aaaaa"

Почему эта программа отображает "aaaaa"? Я понимаю эту программу следующим образом:

  1. CLR резервирует "привет" во внутреннем пуле (я представляю внутренний пул как набор строк).
  2. string.Intern(s) фактически ничего не делает, потому что CLR зарезервировал строку «Hello» - он просто возвращает адрес зарезервированной строки «Hello» (объект s имеет тот же адрес)
  3. Программа изменяет содержимое строки "Hello" с помощью указателя
  4. ??? Строка Hello должна отсутствовать в пуле интерна, и это должно быть ошибкой! Но это нормально; программа работает успешно.

Как я понимаю, внутренний пул - это словно словарь из строки в строку. А может я что то пропустил?

69 голосов | спросил LmTinyToon 19 MonEurope/Moscow2016-12-19T13:00:56+03:00Europe/Moscow12bEurope/MoscowMon, 19 Dec 2016 13:00:56 +0300 2016, 13:00:56

2 ответа


0

Когда вы впервые используете «Hello», он попадает в глобальное хранилище строк приложения. Исходя из того, что вы выполняете в режиме unsafe (подробнее о unsafe здесь ) вы получаете прямую ссылку на данные, хранящиеся в местах, изначально выделенных для значения строки s, поэтому

for (int i = 0; i < s.Length; i++)
      c[i] = 'a';

вы редактируете то, что в памяти. Когда в следующий раз он получит доступ к хранилищу интернированных строк, он будет использовать тот же адрес в памяти, содержащий данные, которые вы только что изменили. Это было бы невозможно без unsafe. string.Intern(s); здесь не играет роли; он ведет себя так же, если вы его закомментируете.

Тогда

Console.WriteLine("Hello"); // Displays: "aaaaa"

.NET проверяет, есть ли запись для адреса, полученного для "Hello" и есть: тот, который вы только что обновили, чтобы он был "aaaaa". Количество символов 'a' определяется длиной "Hello".

ответил Jaroslav Kadlec 19 MonEurope/Moscow2016-12-19T13:31:04+03:00Europe/Moscow12bEurope/MoscowMon, 19 Dec 2016 13:31:04 +0300 2016, 13:31:04
0

Несмотря на то, что @Jaroslav Kadlec правильный и полный, я бы хотел добавьте еще немного информации о поведении кода и почему string.Intern(s); бесполезно в этом случае .

О внутреннем пуле

На самом деле .NET автоматически выполняет интернирование строк для всех строковых литералов, это делается с помощью специальной таблицы, в которой хранятся ссылки на все уникальные строки в нашем приложении.

Однако важно отметить, что только явно объявленная строка интернируется на этапе компиляции .

Рассмотрим следующий код:

var first = "Hello"; //Will be interned
var second = "World"; //Will be interned
var third = first + second; //Will not be interned

Конечно, в некоторых случаях мы бы хотели интернировать некоторую строку во время выполнения, и это можно сделать с помощью String.Intern после проверки с помощью String.IsInterned

Итак, вернемся к фрагменту OP:

//...
var s = "Hello";
string.Intern(s);
//...

В этом случае string.Intern(s); бесполезен, так как он уже интернирован на этапе компиляции.

ответил Sid 23 FriEurope/Moscow2016-12-23T13:50:19+03:00Europe/Moscow12bEurope/MoscowFri, 23 Dec 2016 13:50:19 +0300 2016, 13:50:19

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132