Нет ошибки «Неназначенная локальная переменная»?

#c# #.net #c#-3.0

#c# #.net #c #-3.0

Вопрос:

Почему использование адреса переменной устраняет ошибку «Использование неназначенной локальной переменной»?

(Почему мы можем взять адрес без инициализации в первую очередь?)

 static unsafe void Main()
{
    int x;
    int* p = amp;x;  //No error?!
    x  = 2;       //No error?!
}
  

Комментарии:

1. Заголовок не для тегов, вы знаете, не так ли?:)

2. @abatishchev: Да, я знаю, но я подумал, что это было бы полезно в любом случае. Хотя, тем не менее, спасибо за редактирование. 🙂

3. Вторая часть вашего вопроса, почему мы можем использовать адрес, проста: потому что переменная имеет адрес, независимо от того, присвоили вы ей значение или нет. Но интересно, что компилятор затем считает x инициализированным…

4. Мне кажется, это код C , а не C#

5. @Flawless если бы C требовал, чтобы вы сообщали, когда вы были unsafe тогда программы на C были бы намного длиннее 🙂

Ответ №1:

Спецификация языка C #, раздел 18.5.4:

amp; Оператор не требует, чтобы его аргумент был определенно назначен, но после amp; операции переменная, к которой применяется оператор, считается определенно назначенной в пути выполнения, в котором выполняется операция. Программист несет ответственность за то, чтобы в этой ситуации действительно выполнялась правильная инициализация переменной.

Существуют правила определенного присвоения для оператора amp;, позволяющие избежать избыточной инициализации локальных переменных. Например, многие внешние API принимают указатель на структуру, которая заполняется API. Вызовы таких API обычно передают адрес локальной переменной структуры, и без правила потребовалась бы избыточная инициализация переменной структуры.

Комментарии:

1. О.М.Г … значит, они не шутили насчет «небезопасности» в unsafe блоках!

2. Я должен отметить: при дальнейшем рассмотрении разборки кажется, что CLR все равно инициализирует переменную с помощью .locals init . Так что, может быть, это не так уж и небезопасно в конце концов…

3. @Mehrdad: Похоже, я недостаточно глубоко прочитал; спецификация действительно дает обоснование правилу. Смотрите абзац, который я добавил.

4. @Gabe: Интересно. Но теперь возникает вопрос, ну и что? Что не так с избыточной инициализацией?

5. @Mehrdad: Что с этим не так? Ну, это избыточно. И всего избыточного можно и нужно избегать 🙂 Когда вы программируете на родных языках, таких как C и C , вы учитесь не использовать то, что вам не нужно. Или как говорится в C .. вы платите только за то, что используете.

Ответ №2:

Я думаю, потому что, как только вы взяли указатель на переменную, у компилятора нет возможности проанализировать, присвоено ли значение с помощью этого указателя, поэтому оно исключается из анализа определенного присвоения.

Комментарии:

1. @Damien: Хорошо, конечно, но почему это не заставляет меня сначала инициализировать ее? Разве это не лучше, чем потом сожалеть?

2. @Merhdad — потому что вы едете по бездорожью с небезопасным кодом — возможно, вам нужна каждая унция производительности из этого фрагмента кода — поэтому компилятор, заставляющий вас выполнять дополнительную работу, был бы плохим.

3. @Rick: Разве компилятор C не выдает ошибку, когда видит unsafe ?

4. @Gabe: Я спросил себя, если теория Дэмиена верна, то эквивалентный код C также не выдаст предупреждение компилятором C . У него также возникает та же проблема после получения адреса. Итак, основной код — это часть с отступом. Это то, что я тестировал.