Здравствуйте!
Хочу спросить у знающих людей о передаче параметров в функции на C. Вот есть очень удобный интерфейс у семейства функций printf(char *,...) но я нигде не могу найти как эти три точки принимает функция и преобразует в адреса переменных.
Спасибо большое.
man va_arg
Спасибо, veslo.
Посмотрел я man и не сильно проникся. Есть ли какой-нибудь другой способ передать в функцию произвольный набор параметров без указаний их типов? Можно конечно каждый раз выделять память под структуру а-ля листа и складывать все адреса туда, но, может, есть способ решить проблему уже на этапе компиляции (компилятор то знает сколько параметров передают в конкретном вызове функции).
Спасибо.
>Есть ли какой-нибудь другой способ передать в функцию произвольный набор параметров без указаний их типов?Есть, но не в C.
Вобщем используй va_arg, там ничего страшного.
>компилятор то знает сколько параметров передают в конкретном вызовекомпилятор С ничего не знает про количество аргументов, переданных функции
Почитать про этот механизм можно здесь:
http://www.citforum.ru/security/articles/printf/
http://www.intuit.ru/department/pl/c/9/4.html
>компилятор С ничего не знает про количество аргументов, переданных функции
Почему? Знает. Иначе не смог бы отчистить стек по выходу из функции.
>>компилятор С ничего не знает про количество аргументов, переданных функции
>Почему? Знает. Иначе не смог бы отчистить стек по выходу из функции.
>Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не знать общий размер всех параметров.
>Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не
>знать общий размер всех параметров.
Ну да, вызывающая функция. А кто как не компилятор помещает в неё инструкцию отчистки стека? Я что-то не понимаю как может компилятор не знать про количество параметров, при том что он же помещение этих параметров в стек и компилирует. И потом после вызова функции вставляет очистку стека.
Я думаю Вы что-то другое имели в виду.
>>Не знает. Стек очищает вызывающая функция. Поэтому вызванная функция может даже не
>>знать общий размер всех параметров.
>Ну да, вызывающая функция. А кто как не компилятор помещает в неё
>инструкцию отчистки стека? Я что-то не понимаю как может компилятор неПринимать произвольное число аргументов - свойство вызываемой функции, а не вызывающей. Компилятор ещё ничего не знает про вызывающую.
Переменное число аргументов в современном C (C89 и новее) положено обрабатывать только с помощью stdarg, varagrs типа маст дай.
Потрать полчаса на изучение - там ничего сложного.
> "компилятор С ничего не знает про количество аргументов, переданных
> функции"
Видимо имелось в виду "компилятор С _внутри вызываемой функции_ ничего не знает про количество аргументов, переданных этой функции" , а я подумал почему-то про вызывающую.:confuse:
Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать адрес конца стека то функция типа f(int num,void** stack) будет именно тем что нужно. А можно ли в С узнать адрес стека? Будет ли это &num в принимающей функции?
Спасибо.
>Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать
>адрес конца стека то функция типа f(int num,void** stack) будет именно
>тем что нужно. А можно ли в С узнать адрес стека?
>Будет ли это &num в принимающей функции?
>Спасибо.
Sorry должно быть f(int num,...)
>>Спасибо всем за инфу. У меня возник вопрос по стеку. Если узнать
>>адрес конца стека то функция типа f(int num,void** stack) будет именно
>>тем что нужно. А можно ли в С узнать адрес стека?
>>Будет ли это &num в принимающей функции?
>>Спасибо.
>Sorry должно быть f(int num,...)
да, именно, &num и будет адресом начала стека, а вот с концом, там уже самому надо выдумывать, почитай, я выше давал ссылки,там описывается этот механизм, а вообще, выше писали, для этого есть стандартные решения
Спасибо Brick. Стандартные решения выглядят более запутанными. Я только немного не понял, возможен ли вариант каких-то пробелов между объектами из одного вызова или гарантированно они будут идти друг за другом согласно своим размерам. В ваших ссылках была пара туманных слов о запутанности структуры стека при работе современных компиляторов...
Спасибо.
аргументы в стеке будут идти подряд, один за одним а для разбора параметров существует два класических приема:1) Все аргументы должны быть одного и того же типа и используется какой-нибудь маркер конца списка аргументов, например, f1("arg1", "arg2", ... , "argN", "NULL"), где NULL и будет маркером конца аргументов.
2) Первый, обязательный аргумент может содержать либо количество принимаемых функцией аргументов, если они одного и того же типа, либо, как это используется в семействе функций printf форматная строка, на основе которой ты разбираешь все аргументы, т.е. их типы и количество.
А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными? И еще, как мне передать адрес стека в другую функцию, через void* или есть вариант для "три точки" -> "три точки" напрямую?
Спасибо.
>А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными?
с адресами юудет вс
>А что произойдет со стеком (его конкретным участком, содержащим параметры), если я вызову другую функцию внутри обработчика стека? Будут ли адреса стека и его элементов все еще валидными?
что касается адресов, то всё будет нормально, эти аргументы ничем не отличаются от обычных аргументов функции>И еще, как мне передать адрес стека в другую функцию, через void* или есть вариант для "три точки" -> "три точки" напрямую?
да, через stdarg: http://www.opennet.me/docs/RUS/glibc/glibc-7.html
Спасибо всем (и Brick особенно), теперь понятно.
Всем успехов!