URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 5057
[ Назад ]

Исходное сообщение
"Интерфейс printf"

Отправлено ghost_in_machine , 17-Янв-06 19:42 
Здравствуйте!
Хочу спросить у знающих людей о передаче параметров в функции на C. Вот есть очень удобный интерфейс у семейства функций printf(char *,...) но я нигде не могу найти как эти три точки принимает функция и преобразует в адреса переменных.
Спасибо большое.

Содержание

Сообщения в этом обсуждении
"Интерфейс printf"
Отправлено veslo , 17-Янв-06 23:42 
man va_arg

"Интерфейс printf"
Отправлено ghost_in_machine , 18-Янв-06 13:58 
Спасибо, veslo.
Посмотрел я man и не сильно проникся. Есть ли какой-нибудь другой способ передать в функцию произвольный набор параметров без указаний их типов? Можно конечно каждый раз выделять память под структуру а-ля листа и складывать все адреса туда, но, может, есть способ решить проблему уже на этапе компиляции (компилятор то знает сколько параметров передают в конкретном вызове функции).
Спасибо.


"Интерфейс printf"
Отправлено Аноним , 18-Янв-06 16:28 
>Есть ли какой-нибудь другой способ передать в функцию произвольный набор параметров без указаний их типов?

Есть, но не в C.
Вобщем используй va_arg, там ничего страшного.


"Интерфейс printf"
Отправлено Brick , 19-Янв-06 01:09 
>компилятор то знает сколько параметров передают в конкретном вызове  

компилятор С ничего не знает про количество аргументов, переданных функции

Почитать про этот механизм можно здесь:
http://www.citforum.ru/security/articles/printf/
http://www.intuit.ru/department/pl/c/9/4.html


"Интерфейс printf"
Отправлено Forth , 19-Янв-06 09:09 
>компилятор С ничего не знает про количество аргументов, переданных функции
Почему? Знает. Иначе не смог бы отчистить стек по выходу из функции.



"Интерфейс printf"
Отправлено tilde , 19-Янв-06 09:26 
>>компилятор С ничего не знает про количество аргументов, переданных функции
>Почему? Знает. Иначе не смог бы отчистить стек по выходу из функции.
>

Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не знать общий размер всех параметров.


"Интерфейс printf"
Отправлено Forth , 19-Янв-06 09:39 
>Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не
>знать общий размер всех параметров.
Ну да, вызывающая функция. А кто как не компилятор помещает в неё инструкцию отчистки стека? Я что-то не понимаю как может компилятор не знать про количество параметров, при том что он же помещение этих параметров в стек и компилирует. И потом после вызова функции вставляет очистку стека.
Я думаю Вы что-то другое имели в виду.


"Интерфейс printf"
Отправлено ACCA , 19-Янв-06 12:05 
>>Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не
>>знать общий размер всех параметров.
>Ну да, вызывающая функция. А кто как не компилятор помещает в неё
>инструкцию отчистки стека? Я что-то не понимаю как может компилятор не

Принимать произвольное число аргументов - свойство вызываемой функции, а не вызывающей. Компилятор ещё ничего не знает про вызывающую.

Переменное число аргументов в современном C (C89 и новее) положено обрабатывать только с помощью stdarg, varagrs типа маст дай.

Потрать полчаса на изучение - там ничего сложного.


"Интерфейс printf"
Отправлено Forth , 19-Янв-06 12:31 
> "компилятор С ничего не знает про количество аргументов, переданных
> функции"
Видимо имелось в виду "компилятор С _внутри вызываемой функции_ ничего не знает про количество аргументов, переданных этой функции" , а я подумал почему-то про вызывающую.:confuse:



"Интерфейс printf"
Отправлено ghost_in_machine , 19-Янв-06 12:57 
Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать адрес конца стека то функция типа f(int num,void** stack) будет именно тем что нужно. А можно ли в С узнать адрес стека? Будет ли это &num в принимающей функции?
Спасибо.


"Интерфейс printf"
Отправлено ghost_in_machine , 19-Янв-06 13:00 
>Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать
>адрес конца стека то функция типа f(int num,void** stack) будет именно
>тем что нужно. А можно ли в С узнать адрес стека?
>Будет ли это &num в принимающей функции?
>Спасибо.
Sorry должно быть f(int num,...)


"Интерфейс printf"
Отправлено Brick , 19-Янв-06 14:39 
>>Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать
>>адрес конца стека то функция типа f(int num,void** stack) будет именно
>>тем что нужно. А можно ли в С узнать адрес стека?
>>Будет ли это &num в принимающей функции?
>>Спасибо.
>Sorry должно быть f(int num,...)
да, именно, &num и будет адресом начала стека, а вот с концом, там уже самому надо выдумывать, почитай, я выше давал ссылки,там описывается этот механизм, а вообще, выше писали, для этого есть стандартные решения

"Интерфейс printf"
Отправлено ghost_in_machine , 19-Янв-06 15:29 
Спасибо Brick. Стандартные решения выглядят более запутанными. Я только немного не понял, возможен ли вариант каких-то пробелов между объектами из одного вызова или гарантированно они будут идти друг за другом согласно своим размерам. В ваших ссылках была пара туманных слов о запутанности структуры стека при работе современных компиляторов...
Спасибо.  



"Интерфейс printf"
Отправлено Brick , 19-Янв-06 15:51 
аргументы в стеке будут идти подряд, один за одним а для разбора параметров существует два класических приема:

1) Все аргументы должны быть одного и того же типа и используется какой-нибудь маркер конца списка аргументов, например, f1("arg1", "arg2", ... , "argN", "NULL"), где NULL и будет маркером конца аргументов.

2) Первый, обязательный аргумент может содержать либо количество принимаемых функцией аргументов, если они одного и того же типа, либо, как это используется в семействе функций printf форматная строка, на основе которой ты разбираешь все аргументы, т.е. их типы и количество.


"Интерфейс printf"
Отправлено ghost_in_machine , 19-Янв-06 16:07 
А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными? И еще, как мне передать адрес стека в другую функцию, через void* или есть вариант для "три точки" -> "три точки" напрямую?
Спасибо.



"Интерфейс printf"
Отправлено Brick , 19-Янв-06 16:41 
>А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными?
с адресами юудет вс

"Интерфейс printf"
Отправлено Brick , 19-Янв-06 16:48 
>А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными?
что касается адресов, то всё будет нормально, эти аргументы ничем не отличаются от обычных аргументов функции

>И еще, как мне передать адрес стека в другую функцию, через void* или есть вариант для "три точки" -> "три точки" напрямую?
да, через stdarg: http://www.opennet.me/docs/RUS/glibc/glibc-7.html


"Интерфейс printf"
Отправлено ghost_in_machine , 19-Янв-06 17:00 
Спасибо всем (и Brick особенно), теперь понятно.
Всем успехов!