Подтвердить что ты не робот

Требуется ли инструкция ret для приложений .NET?

Я заметил, что компилятор С# генерирует команду ret в конце методов void:

.method private hidebysig static void Main(string[] args) cil managed
{
    // method body
    L_0030: ret 
} 

Я написал компилятор для .NET, и он работает независимо от того, испускал ли я оператор ret или нет (я проверил сгенерированный IL, и он действительно не там).

Я просто задаюсь вопросом: требуется ли ret для методов, возвращающих void для чего-либо? Кажется, он ничего не делает со стек, поэтому я считаю, что это совершенно не нужно для методов void, но я хотел бы услышать от кого-то, кто знает немного больше о CLR?

4b9b3361

Ответ 1

Согласно стандарту С# (ECMA-334), метод определяется следующим образом:

Метод - это элемент, который реализует вычисление или действие, которое может быть выполнено объектом или классом. Методы имеют (возможно, пустой) список формальных параметров, возвращаемое значение (если только методы return-type не являются void) и являются либо статическими, либо нестатическими.

(ECMA-334; 8.7.3: Методы).

Теперь стандарт CLI определяет следующее:

Управлению не разрешается просто "проваливать" конец метода. Все пути должны заканчиваться с одной из следующих инструкций: ret, throw, jmp или (tail, затем вызов, calli или callvirt).

(ECMA-335; 12.4, 6)

Это означает, что в С# метод, возвращающий void, не нуждается в операторе return. Однако, поскольку компилятор С# компилирует код С# в IL-код, который требует завершения пути в конце метода, он испускает ret для завершения метода.

Ответ 2

Это действительно необходимо для проверки кода. В противном случае PEVerify выведет следующее сообщение об ошибке:

[IL]: Ошибка: [(filename): (methodname)] [offset 0x00000000] проваливается в конец метода без возврата

Ответ 3

Из Ecma-335. (12.4, 6)

Управлению не разрешается просто "проваливать" конец метода. Все пути должны заканчиваться с одной из следующих инструкций: ret, throw, jmp или (tail, затем вызов, calli или callvirt).