|
|
Регистрация Восстановить пароль |
Повторная активизация e-mail |
Регистрация | Задать вопрос |
Заплачу за решение |
Новые сообщения |
Сообщения за день |
Расширенный поиск |
Правила |
Всё прочитано |
|
Опции темы | Поиск в этой теме |
12.01.2014, 15:36 | #1 |
Форумчанин
Регистрация: 14.12.2012
Сообщений: 668
|
Функции - передача параметров
Изучал передачу параметров в функции через стек и остался очень удивленным (может баг компилятора?). Я считал что порядок аргументов в стеке строго регламентирован (__cdecl, __stdcall, ...) и стек растет квантами по 4 байта, т.е. для 5 байтовый массив займет в стеке 8 байт. Следующий код разрушил все мои представления:
Код:
Код:
Код:
|
12.01.2014, 16:31 | #2 | |
Старожил
Регистрация: 16.12.2011
Сообщений: 2,329
|
Цитата:
Это означает "хер знает, как именно компилятор их там пакует и вычисляет, но проблемы мы не ожидаем". На практике проблемы начинаются при попытке сишными хаками пытаться дотянуться до аргументов прямо на стеке функции (да да, именно так, как это сделали вы - нельзя). Какие нибудь константные аргументы он вообще может закинуть куда нибудь в регистры только чтения и попытка взять адрес завершится аварией. К слову: я када то пробовал исследовать входные аргументы на стеке функции компилятором мелкомягких, методом научного тыка установил - в зависимости от различных типов аргументов функции, они могут располагаться по самым разным адресам. И далеко не факт, что это будет непрерывный блок памяти. Код:
Что бы лазить по стеку существует православный сишный костыль - макросы: va_list, va_start, va_end Код:
Код:
Последний раз редактировалось _Bers; 12.01.2014 в 16:40. |
|
12.01.2014, 19:03 | #3 |
Форумчанин
Регистрация: 14.12.2012
Сообщений: 668
|
Это какая-то магия )). Подключил к приложению написанному на MSVC dll (написанную на gcc), думал будут какие-нибудь косяки с аргументами. Не знаю как, но все правильно связалось.
Последний раз редактировалось 220Volt; 12.01.2014 в 19:08. |
13.01.2014, 21:44 | #4 |
Участник клуба
Регистрация: 23.12.2010
Сообщений: 1,129
|
Дело не в порядке вычисления, а в порядке складывания аргументов в стек. И он как раз четко задан в calling convention. cdecl значит "никаких констант в регистрах, все только в стеке, справа налево".
По теме: 1) Майкрософтовский компилятор сделал все предсказуемо (4 байта разницы, как и должно быть при выравнивании на 4). 2) gcc в первой функции зачем-то сделал так: Код:
У гцц много подобных идиосинкразий в кодогенераторе, потому не ищи в этом смысла. Если собрать со включенной оптимизацией - результат станет правильным (-4 -4). 3) Ну а шланга у меня под рукой нет. Подозреваю, что он поступил как и gcc. p. s. Дизассемблер - очень полезная штука в таких случаях, да. |
14.01.2014, 12:22 | #5 |
Форумчанин
Регистрация: 14.12.2012
Сообщений: 668
|
Спасибо, теперь ясно. Я уже подумал что соглашения о вызовах отменили ))
|
14.01.2014, 12:38 | #6 | |
Старожил
Регистрация: 28.01.2009
Сообщений: 21,000
|
Цитата:
он может создать временные переменные для применения аргументов. Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел. Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите. |
|
15.01.2014, 02:25 | #7 | |
Старожил
Регистрация: 16.12.2011
Сообщений: 2,329
|
Цитата:
А потом попытайтесь вытащить эти типы со стека: Код:
Я когда то (с++03) изготавливал делегаты. Одно из требований к дизайну было - простота использования. Поэтому делегат был не шаблонном класса, а обычным. Все факты использования шаблонов прятались за счет вывода типов аргументов из аргументов функций: Код:
Код:
Там под капотом аргументы могут пройти по целой цепочке функций, пока дойдут до окончательного шаблоно-исполнителя. Вопрос: как это сделать так, что бы по возможности избежать лишних копирований аргументов? Я думал, что проще просто передать адрес, откуда якобы начинается самый первый аргумент функции. Конечный исполнитель зная точно с какими типами данных он работает, мог бы вытряхнуть все остальные данные прямо со стека функции. И это действительно работало. Правда только в дебаг-версии, и то - далеко не всегда. Если все аргументы инты - вроде бы работало. Стоит подмешать туда какой нибудь указатель, и вместо него при извлечении получался мусор. Про релиз версию вообще молчу. Я так и не разобрался до конца с этим вопросом. Мой тимлид мне порекомендовал не пытаться оптимизировать на спичках, изготавливая мутные и потенциально небезопасные хаки на грани UB А вместо этого сделать так: Код:
void Foo( ... ); Сишное наследие, умеют принимать любое количество любых аргументов. И я сейчас не скажу вам точно с чем это связанно, но совершенно точно скажу: во всех книжках пишут, что стандартные макросы для лазинья по стеку - единственный корректный (кросс-платформеный, гарантированно безопасный с точки зрения манипуляций со стеком) способ. Поэтому, собственно, я бросил заниматься этой ерундой и больше никогда не пытался сишными хаками долбать стек. |
|
15.01.2014, 10:12 | #8 |
Старожил
Регистрация: 13.07.2012
Сообщений: 6,330
|
|
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
JQuery: передача параметров функции | zizz | JavaScript, Ajax | 2 | 31.10.2013 20:10 |
передача функции в качестве параметров функций, С++ | prettynetty | Помощь студентам | 2 | 17.03.2012 20:11 |
Передача параметров | _Mixer_ | Общие вопросы по Java, Java SE, Kotlin | 0 | 22.09.2011 20:17 |
Передача параметров в функции(Одинаковые имена дефолта и передаваемого параметра) это плохо? | Человек_Борща | Общие вопросы Delphi | 3 | 13.04.2011 16:54 |
Передача параметров функции | Кипящий чайник | Общие вопросы C/C++ | 12 | 11.08.2010 19:45 |