avva: (Default)
[personal profile] avva
(эта запись будет интересна программистам, знающим C, и сочувствующим)

Две задачки - первая старая и известная, вторую только что придумал.

1. Напишите код на C, который определяет, в какую сторону растет стек на машине, где его запустили - вверх или вниз.

2. Напишите код на C, который проверяет, кто очищает стек от аргументов в конце работы функции - сама функция или тот, кто ее вызывает, после ее возвращения.

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

Комментарии скрывать не буду. Очень рекомендую подумать самому перед тем, как смотреть на решения там.
Page 1 of 5 << [1] [2] [3] [4] [5] >>

Date: 2009-09-17 09:38 am (UTC)
From: [identity profile] psilogic.livejournal.com
1. Объявить авто-переменную, узнать адрес, вызвать функцию, в ней объявить еще одну авто-переменную, узнать адрес, сравнить адреса.

На C++, наверное, можно проще, без вызова функций, так как можно что-то делать в промежутках между объявлениями переменных. Но вдруг компилятор захочет что-нибудь соптимизировать и переставить переменные. А с вызовом функции - практически гарантия.

Date: 2009-09-17 09:42 am (UTC)
From: [identity profile] pargentum.livejournal.com
Первая задача достаточно проста.

А вот вторая, как я понимаю, без привлечения знаний об устройстве компилятора неразрешима. Особенно если компилятор передает часть параметров через регистры.

Date: 2009-09-17 09:45 am (UTC)
From: [identity profile] avva.livejournal.com
Да, это верно. Давайте предположим, что все аргументы передаются через стек. Update: думаю, что на практике это можно навязать с помощью volatile.
Edited Date: 2009-09-17 09:48 am (UTC)

Date: 2009-09-17 09:51 am (UTC)
From: [identity profile] avva.livejournal.com
Да, все правильно, согласен также с использованием вызова функции (его можно устроить рекурсивным, если хочется). Полагаться на порядок расположения локальных переменных не хочется.

Date: 2009-09-17 09:52 am (UTC)
ext_475885: (Default)
From: [identity profile] brewbuilder.livejournal.com
1. тривиально (см ответ первого ответившего)
2. от локальных автоматических переменных всегда сама функция,
от переданных параметров всегда тот, кто вызывает (если речь идет о C).
Догадайтесь почему, и еще догадайтесь, зачем параметры пихаются
в обратном порядке :)

Date: 2009-09-17 09:52 am (UTC)
From: [identity profile] kcmamu.livejournal.com
А разве невозможны архитектура и компилятор, обходящиеся вообще без стека?

Date: 2009-09-17 09:53 am (UTC)
ext_475885: (Default)
From: [identity profile] brewbuilder.livejournal.com
Вторая вообще не загадка, поскольку может быть
только один вариант (догадайтесь почему)

Date: 2009-09-17 09:56 am (UTC)
From: [identity profile] avva.livejournal.com
Возможны, поэтому я добавил 'совсем без этого не обойтись' в условии. Просто давайте решать задачу, предполагая, что стек используется достаточно стандартным способом.

Date: 2009-09-17 09:59 am (UTC)
From: [identity profile] avva.livejournal.com
да, а "очищает" я имел в виду от аргументов, а не локальных переменных - добавил это в условие, чтобы не было неясности.

Date: 2009-09-17 10:02 am (UTC)
ext_475885: (Default)
From: [identity profile] brewbuilder.livejournal.com
По любому, это не стандартный C'шный вызов,
для функции с переменным чистом аргументов он
использован быть не может. Более того
обычный C не требует прототипов вызываемых функуций,
а stdcall без прототипов не возможен.
Так что речь о "pure С" не идёт.

Date: 2009-09-17 10:02 am (UTC)
From: [identity profile] pargentum.livejournal.com
Поскольку стандарт языка С допускает вызов функций с иным количеством параметров, чем задано при определении функции, единственный возможный механизм передачи параметров через стек - это обратный порядок, когда последний параметр проталкивается первым. Определить порядок проталкивания параметров несложно, но это ничего не говорит о том, кто чистит стек.

Из-за возможного разнобоя в количестве параметров стек либо должен чиститься вызывающей функцией, либо в стеке должен передаваться объем блока параметров (и тогда его может чистить вызванная функция). Различить эти два поведения программой на языке С невозможно: дополнительные поля в стековом кадре могут использоваться и для целей, не связанных с передачей параметров (например, сохраненные регистры или exception handlers в VMS/OS/2/Win32)

Date: 2009-09-17 10:03 am (UTC)
From: [identity profile] pargentum.livejournal.com
Это паскалевское соглашение о вызовах, а не cшное.

Date: 2009-09-17 10:06 am (UTC)
ext_475885: (Default)
From: [identity profile] brewbuilder.livejournal.com
уже написал :)

Date: 2009-09-17 10:07 am (UTC)
From: [identity profile] avva.livejournal.com
Знаете, до вас уже один юзер оставил ровно такой же комментарий, и я хотел его попросить пойти по данной ссылке и прочитать хотя бы первый (или второй) результат. Но, видимо, он сам догадался это сделать, потому что свой комментарий стер до того, как я успел ответить.

Date: 2009-09-17 10:13 am (UTC)
From: [identity profile] pargentum.livejournal.com
http://avva.livejournal.com/2137625.html?thread=64932121#t64932121

Скажем, в VMS (не только на ваксе) в блоке параметров всегда передается его размер.

Впрочем, в VMS, насколько я помню, стек всегда чистится вызывающей функцией, но по другой причине - там аргументы могут быть вообще не в стеке. :)

Date: 2009-09-17 10:19 am (UTC)
From: [identity profile] pargentum.livejournal.com
Я знаю что такое stdcall и еще помню времена, когда вместо этого слова использовалось слово PASCAL. :)

Date: 2009-09-17 10:21 am (UTC)
From: [identity profile] mgar.livejournal.com
Не просто не хочется, а будет неправильным - встречались мне компайлеры, которые тасовали переменные как хотели.

ЗЫ

Date: 2009-09-17 10:22 am (UTC)
From: [identity profile] pargentum.livejournal.com
Вторая ссылка гугля:
stdcall

The stdcall[1] calling convention is a variation on the pascal calling convention in which parameters are passed on the stack, pushed right-to-left. Registers EAX, ECX, and EDX are designated for use within the function. Return values are stored in the EAX register. The callee is responsible for cleanup of the stack.

Stdcall is the standard calling convention for the Microsoft Win32 API.

Date: 2009-09-17 10:23 am (UTC)
From: [identity profile] cmm.livejournal.com
1. ну понятно
2. единственное что приходит в голову — это проверить работает ли хвостовая рекурсия для функций с постоянным количеством аргументов.  если работает, значит функции чистят за собой сами; если нет, то либо копилятор не фонтан, либо чистит зовущий. :)

Date: 2009-09-17 10:25 am (UTC)
From: [identity profile] avva.livejournal.com
pascal и stdcall в разном порядке толкают аргументы в стек.

Re: ЗЫ

Date: 2009-09-17 10:33 am (UTC)
From: [identity profile] avva.livejournal.com
Это не "паскалевское соглашение", как вы написали, а cоглашение, использующееся в c/c++ под windows, и являющееся гибридом паскалевского и cdecl. Я не понимаю, о чем идет спор. Если вы знаете, что под windows (например), функции могут быть скомпилированы как в cdecl, так и в stdcall, и на практике используются оба соглашения, то почему бы не подумать, как я предлагаю, о том, можно ли написать код, различающий эти два случая? К чему весь этот срач в стиле "я знаю о C больше, чем ты"?

I can't believe I'm participating in this jerkfest. Sheesh.

Date: 2009-09-17 10:33 am (UTC)
From: [identity profile] mgar.livejournal.com
1 - элементарно,

2 - делаем следующим образом. Первым делом пишем две функции - первая возвращает current stack (адрес локальной переменной), вторая - dummy function без параметров.

Теперь делаем так - запоминаем current stack, затем вызываем dummy, которую кастингом приводим к функции с одним параметром. Затем снова вызываем current stack. Если оба раза стэк одинаков = мы его и чистим. Если стэк вырос - мы положились на вызываемую функцию.

Теперь осталось только подчистить за собой стек во втором случае.

(Метод не чистый, потому что посередине у нас есть участок кода, где стек не валидный, и теопретически это может нас грохнуть, но по идее там ничего нам из стека не надо...)

PS. А по идее, обе функции - current stack и dummy - могут быть одной и той же.

Date: 2009-09-17 10:35 am (UTC)
From: (Anonymous)
2. При вызове сишной функции (то есть такой, которая объявлена без pascal, inline, fastcall и т. д.) стек всегда очищает вызывающий. Иначе бы вот такой (законный) код

int f(...) { return 0; }

int main() { f(1); f(1, 2); f(1, 2, 3); return 0; }

нельзя было бы корректно откомпилировать.

Date: 2009-09-17 10:39 am (UTC)
From: [identity profile] avva.livejournal.com
Полчаса назад вы не знали о существовании stdcall. В этом нет ничего страшного, многие программисты на C не знают о разных соглашениях вызова, это довольно-таки низкого уровня знание. Но если уж вам объяснили и дали ссылку, то резоннее было бы отреагировать в духе "спасибо, не знал", а не: 1) написать бред, не читая; 2) стереть его; 3) написать комментарий в духе "все равно я в белом, а вы в дерьме".

Больше я с вами на эту тему общаться на буду, и если вы будете продолжать вести себя как тролль, забаню. У меня нет времени на пенисомерки.

По сути дела: стандарты C ничего не говорят про стек и способы передачи аргументов, поэтому говорить о "стандартном вызове" и "pure C" в контексте данной записи - нелепо. Кроме того, чистка стека фунцкией совместима
с переменным числом аргументов, просто требует предоставить функции информацию об их числе в каждом случае с помощью дополнительного скрытого бухгалтерского аргумента.
Page 1 of 5 << [1] [2] [3] [4] [5] >>

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 29th, 2025 01:11 pm
Powered by Dreamwidth Studios