задачки про стек (программистское)
Sep. 17th, 2009 12:19 pm(эта запись будет интересна программистам, знающим C, и сочувствующим)
Две задачки - первая старая и известная, вторую только что придумал.
1. Напишите код на C, который определяет, в какую сторону растет стек на машине, где его запустили - вверх или вниз.
2. Напишите код на C, который проверяет, кто очищает стек от аргументов в конце работы функции - сама функция или тот, кто ее вызывает, после ее возвращения.
Обратите внимание, что обе задачи можно решить многими способами; интересней придумать решения, которые делают - по возможности, т.к. совсем без этого не обойтись - меньше предположений о том, как ведут себя компилятор и железо.
Комментарии скрывать не буду. Очень рекомендую подумать самому перед тем, как смотреть на решения там.
Две задачки - первая старая и известная, вторую только что придумал.
1. Напишите код на C, который определяет, в какую сторону растет стек на машине, где его запустили - вверх или вниз.
2. Напишите код на C, который проверяет, кто очищает стек от аргументов в конце работы функции - сама функция или тот, кто ее вызывает, после ее возвращения.
Обратите внимание, что обе задачи можно решить многими способами; интересней придумать решения, которые делают - по возможности, т.к. совсем без этого не обойтись - меньше предположений о том, как ведут себя компилятор и железо.
Комментарии скрывать не буду. Очень рекомендую подумать самому перед тем, как смотреть на решения там.
no subject
Date: 2009-09-17 10:41 am (UTC)no subject
Date: 2009-09-17 11:07 am (UTC)Вы об этом?
Кроме того, чистка стека фунцкией совместима с переменным числом аргументов, просто требует предоставить функции информацию об их числе в каждом случае с помощью дополнительного скрытого бухгалтерского аргумента.
Ну, можно и так. Создатели VisualC пошли более простым путем: если я компилирую вышеприведенный код с указанием, что соглашение вызова по умолчанию - stdcall, то компилятор все равно компилирует все, что связано с f(...) как cdecl. То есть стек чистит по-прежнему вызывающий.
no subject
Date: 2009-09-17 11:25 am (UTC)no subject
Date: 2009-09-17 11:50 am (UTC)Вот и мне кажется, что это правильно. Скажем так, cdecl - наиболее естественное для С соглашение о вызове.
Вот, кстати, еще один (законный) кусок кода:
int main() { f(0); f(0, 1); f(0, 1, 2); }
int f(int x, int y) { return 0; }
Здесь на момент компиляции main не известно, сколько аргументов у f, и - более того - даже не известно, имеет ли f фиксированное или переменное число аргументов (так что если для функций с переменным числом аргументов используется "хитрый трюк", то мы все равно не знаем, надо ли здесь применять этот трюк). Если мы считаем, что функция - cdecl, проблемы нет: мы можем сгенерировать код, который не будет вызывать никаких проблем со стеком. Но если функция не cdecl, откомпилировать main становится затруднительно (если в VisualC указать, что соглашение по умолчанию - stdcall, то это и не компилируется).
Ну и переопределения типа функций будет вызвать проблемы со стеком (по наличию которых выше и предлагается определять используемое соглашение вызова).
Так что мне очень трудно представить себе, что может толкнуть создателей компилятора на отказ от cdecl, как "естественного" соглащения вызова.
Конечно, задачу 2 можно переформулировать как-то так: "написать код, который определяет, какое соглашение вызвова по умолчанию использовалось при компиляции этого кода" - это позволяет избавиться от неявного допущения, что компилятор писали люди, не ищущие легких путей.
no subject
Date: 2009-09-17 11:59 am (UTC)no subject
Date: 2009-09-17 12:33 pm (UTC)