Няма директен начин за функция, която използва va_arg
за определяне на броя или типа(овете) на аргументите, предадени от дадено извикване.
Предложеният от вас метод по-специално:
while(va_arg(argPtr, char) != NULL)
е неправилно. va_arg(argPtr, char)
дава стойност от тип char
, докато NULL
е константа с нулев указател. (NULL
обикновено се дефинира като 0
, което се сравнява с нулевия знак '\0'
, но не можете да разчитате на това.)
Всяка променлива функция трябва да има начин за извикващия да указва броя и типовете аргументи. Функциите *printf
, например, правят това чрез (непроменлив) форматиращ низ. Функциите POSIX execl*()
очакват поредица от char*
аргументи; краят на списъка с аргументи се маркира от извикващия с (char*)NULL
. Възможни са и други методи, но те почти всички зависят от информацията, дадена по време на изпълнение в аргументите. (Вие можете да използвате някакъв друг метод, като например глобална променлива. Моля, недейте.)
Това натоварва извикващия да гарантира, че аргументите, предадени на функцията, са последователни. Самата функция няма начин да потвърди това. Неправилните повиквания, като printf("%d\n", "hello")
или execlp("name", "arg1")
, имат недефинирано поведение.
Още нещо: не можете да използвате va_arg
с аргумент от тип char
. Когато извиквате променлива функция, аргументите, съответстващи на , ...
, се повишават. Целочислените аргументи от типове, по-тесни от int
, се повишават до int
или unsigned int
, а аргументите от тип float
се повишават до double
. Ако повикващият предаде аргумент от тип char
, функцията трябва да извика va_arg(argPtr, int)
.
(При много неясни обстоятелства, на които е малко вероятно да попаднете, char
може да бъде повишен до unsigned int
. Това може да се случи само ако обикновеният char
е без знак и sizeof (int) == 1
, което означава, че един байт е поне 16 бита.)
person
Keith Thompson
schedule
20.05.2016
n
е форматиращ низ, тогава обикновено бихте се държали катоprintf
и семейство, като съпоставите броя на спецификаторите на формат с броя на параметрите. Сигурни ли сте, че се предава само променлив бройchar
s? Ако е така, можете да съпоставите-1
или0
или нещо подобно, но NULL е лоша идея поради причините, посочени от @hvd в неговите коментари по-долу. - person Ryan Haining   schedule 21.05.2016char
стойности, тогава трябва да използватеsigned char
, ако имате работа само със стойности в диапазона [0, 128) (ascii), тогава -1 трябва да е добре. - person Ryan Haining   schedule 21.05.2016char
аргументи, защо просто не подадете низ? (Има някои случаи, в които това няма да работи, но това е очевидното решение.) - person Keith Thompson   schedule 21.05.2016int
стойности, тогава трябва да изберете някаква специалнаint
стойност като 0 или -1. Ако предавате низове, т.е.char *
, тогава трябва да го прекратите с(char *) NULL
, както например изискваexecl()
. - person Tom Karzes   schedule 21.05.2016