Причина проста: аргументы функции помещаются в стек вызывающей функцией (единственной, кто может это сделать, потому что только у нее есть необходимая информация; в конце концов, весь смысл этого в том, чтобы передать эту информацию в называется функцией). Адрес возврата помещается в стек механизмом вызова функции. Функция вызывается после того, как вызывающая функция установила параметры, потому что после вызова выполняется вызываемая функция, а не вызывающая.
Итак, теперь вы можете возразить, что вызывающая функция может поместить параметры за пределы используемого в настоящее время стека, а вызываемая функция может затем просто изменить указатель стека соответствующим образом. Но это не сработает, потому что в любой момент может быть прерывание или сигнал, который затолкнет текущее состояние в стек, чтобы восстановить его позже (я не удивлюсь, если переключение задач тоже сделает это) . Но если вы настроите параметры за пределами текущего стека, эти асинхронные события перезапишут его, и, поскольку вы не можете предсказать, когда они произойдут, вы не сможете этого избежать (кроме отключения, которое может иметь другие недостатки или даже быть невозможным, в случае переключателя задач). По сути, все, что находится за пределами текущего стека, должно считаться изменчивым.
Также обратите внимание, что это не зависит от вопроса о том, кто очищает параметры. В принципе, вызываемая функция может вызывать деструкторы вызовов аргументов, даже если физически они лежат во фрейме стека вызывающего объекта. Кроме того, многие процессоры (включая x86) имеют инструкции, которые автоматически добавляют дополнительный пробел перед адресом возврата при возврате (например, компиляторы Паскаля обычно делали это, потому что в Паскале у вас нет никакой очистки, кроме возврата памяти, и, по крайней мере, для процессоров того времени было более эффективно выполнять очистку с помощью этой инструкции процессора (я понятия не имею, верно ли это для современных процессоров).Однако C не использовал этот механизм из-за списков аргументов переменной длины: этот механизм был неприменим, потому что вам нужно было бы знать во время компиляции, сколько дополнительного пространства освобождается, а K&R C не требовал опережающего объявления функций с переменным числом переменных (C89 делает это, но лишь немногие компиляторы используют это в своих интересах из-за совместимости со старым кодом), поэтому у вызывающей функции не было возможности узнать, нужно ли очищать аргументы, если только она не должна была делать это всегда.
person
celtschk
schedule
12.02.2012