когда есть stack unwinding и stacktrace. Какой практический смысл отрицать существование абстракции которой оперируют оба этих конструкта?
но ведь они не оперируют этой абстракцией
Если предположить что у нас нет стека вызовов и контрол флоу реализован любым другим способом, то есть мы можем нарушать правило, что мы возвращаем управление вызывающему коду. Условно говоря вместо обычной структурированный программы в c++ мы взяли и поехали на setjmp/longjmp во все стороны. Что-нибудь из того что описано стандартом в c++ все еще будет иметь смысл? Automatic storage duration? stack unwinding? std::stacktrace? Не будет, так как такая ситуация описана как ub. Даже return теряет смысл. Просто мы почему то не называем стек вызовов стеком вызовов в этом случае. Непонятно почему.
ваше предположение звучит так, будто подход к реализации — стек — обеспечивает семантику тому же return, что очевидно не так. семантика прописана в стандарте, и если реализация творит дичь, то она попросту не соответствует стандарту в стандарте уже было понятие о потоке управления, функциях, их вызове и возврате, и на основе такого понятийного аппарата вполне можно сформулировать семантику std::stacktrace не прибегая к стеку, что мы и наблюдаем в тексте
никто не говорит что фреймы должны лежать гдето вместе например
А я не вижу смысла обсуждения стека в чате по С/С++, когда такого понятия нет в определении языка.
Ты удивишься, но существуют ЭВМ, где НЕТ сегмента стека и регистра SP, и для передачи управления в вызываемую функцию и из неё используются другие принципы. Именно поэтому и нет смысла обсуждать какой-то там стек какого-то там процессора Intel
Семантика return вернуть управление вызывающему коду. Call stack структура данных описывающая отношение вызывающего кода и вызываемого кода, без разницы как она реализована. Речь идет не об имплементации в каждой конкретной вм. Какой смысл имеет return если у вас нет call stack'а?
Все ещё не понимаю как call stack и return связаны
return - вернись в точку вызова
У вас в стек-фрейме имеются локальные переменные функции, адрес возврата и параметры функции.
Тут разговор в рамках стандарта
https://blog.panicsoftware.com/coroutines-introduction/ Закину на всякий случай
И что, по-другому реализовать никак нельзя?
Очень странный вопрос. А как вы собираетесь вернуться назад в точку выполнения своего без сохранения контекста выполнения?
Такой же как и если бы он был
Есть платформы где стека нет в принципе. Например первые моменты работы BIOS есть доступ только к регистрам, а память ещё не проинициализирована. C++ на таких платформах работает BTW
Антон, на ЕС-ЭВМ вообще нет (не было) стека, там используются связанные списки блоков PSB
а как под такие платформу плюсы компилят? там же наверняка свой компиль, который учитывает особенность железки и вместо принятых в х86 инструкций и регистров для стэка использует что-то другое?
Не компиль, линковщик. Для DOS был такой формат исполняемых файлов — com. Размером 64К максимум, и стек там шел с обратного конца от этих 64К. Ничто не помешает на какой-нибудь атмеге стек тоже организовать с обратного конца от RAM.
Я скорее не про отсутствие sp регистров в вм, а про то что структура данных, которая хранит адреса возврата все равно есть, и она lifo. Она может быть в дженерик регистрах, не обязательно в памяти. Иначе как мы можем возвращаться к вызываемому коду?
это совсем о другом) это про структуру данных как абстракицю и как её использовать и где)
Да и вообще говоря, джампы это повод очень хорошо задуматься о происходящем.
не обязательно Можно например все вызовы всегда инлайнить => stacktrace получать по указателю на инструкцию, а не по указателю на начало стек фрейма
Ну согласен, единственное что такой таргет не сможет в динамические библиотеки, но их в стандарте тоже нет, поэтому все хорошо
Хотя что делать с рекурсиями, которые не развернуть в циклы?
либо превращать в цикл и инлайнить вызовы, либо падать с ошибкой компиляции
Но разве с точки зрения языка рекурсия это ошибка компиляции? Если мы говорим что это так на конкретной платформе, значит платформа может только в сабсет c++, получается без стека вызовов мы не можем получить полноценный с++ на этой платформе
Можно ограничить через количество аргументов для функции, выдав их меньше чем регистров в системе, оставшиеся регистры использовать для треканья стейта рекурсии https://eel.is/c++draft/implimits#2.12 Ну и тут вообще позволяют делать имплементорам что угодно, лишь бы было задокументировано https://eel.is/c++draft/implimits#2
Ты если исключения отключаешь или RTTI уже получаешь не полноценный С++. И во всяких эмбедед так и делают.
Да можно и всю std выкинуть, но ничто не мешает реализовать что rtti, что исключения на платформе, делают так из соображений рационального использования памяти, проца. Ну и кому то контрол флоу исключений не нравится.
Ну 2.12 же про другое, если ваш компилятор решил аллоцировать регистры под стейт рекурсии, то сколько этого стейта понадобится, все равно станет известно только в рантайме же, в зависимости от глубины. Ну и какой мне код то сгенерить если я глубину узнаю в рантайме? На n уровней, а дальше крашнуться?
Но ведь щас и в обычной ситуации так и происходит :)
Естественно, просто в этом случае мы решение принимаем во время компиляции, когда генерим код. От того что мы в рантайме выжрали стек и упали у нас не пухнет бинарь.
Имхо, исключения - несоизмеримо более серьезная потеря, нежели RTTI
.model tiny молодость на Atmega8 так и сделано: стек с конца срама
любую рекурсию можно реализовать через цикл. Пока видимое поведение программы не изменяется — с точки зрения компилятора и стандарта всё ОК.
Именно, с помощью стека сохраняя стейт
Выбор абстракции непринципиален. Абсолютно ничего не мешает сохранять с помощью того же линкедлиста. Или, как в стандартном std::stack, с помощью дека.
может потому что нет такого различия для некоторых устройств?
Обсуждают сегодня