2014-10-22 3 views
0

Я пытаюсь написать вариацию Printf, где элемент печатаемый и формат печатаемые являются смежными параметры в вызове, как ...vprintf не потребляя вещь va_list

print(2, "%s", "hello", "%.5u", 25); 

Я изучал на вар арг и придумал ....

void print(int count, ...) 
{ 
    va_list varg; 
    va_start(varg, count); 

    while(count-- > 0) 
    { 
     char* format = va_arg(varg, char*); 
     vprintf(format, varg); 
    }    

    va_end(varg); 
} 

оказывается, что vprintf не потребляя предмет, который он использует из стека. Мой выход

hellohello

Я считаю, что это расширяется слишком

printf("%s", "hello); 
printf("hello"); 

Так что я делаю неправильно, что vprintf не потребляя «привет» из списка агд?

Update: в комментарии ниже

void print(int count, ...) 
{ 
    va_list varg; 
    va_start(varg, count); 

    while(count-- > 0) 
    { 
     char* format = va_arg(varg, char*); 
     void* arg = va_arg(varg, void*); 
     printf(format, arg); 
    }    

    va_end(varg); 
} 

Это, кажется, чтобы получить работу.

+1

Я бы не рассчитывал на то, что работает на всех системах, поскольку тип, предоставляемый va_arg, должен быть фактическим типом аргумента. Цитируя стандарт: «Если фактический следующий аргумент отсутствует, или если тип несовместим с типом фактического следующего аргумента (в соответствии с продвижением по умолчанию), поведение не определено».Предусмотрены два исключения: void * и char * являются взаимозаменяемыми; и беззнаковые и подписанные типы взаимозаменяемы, если значение положительное. – rici

ответ

1

Va_list - это не что иное, как адрес (в типичных реализациях). Он передается по значению функции, поэтому оригинал в вызывающей функции не модифицируется.

+0

Я вижу. Поэтому мое предположение было неправильным. –

1

Что вы здесь делаете, это неопределенное поведение. В стандарте C99, пункт 3 раздела 7,15, он говорит:

тип объявлен в va_list который является тип объекта, пригодного для хранения информации, необходимой макросов va_start, va_arg, va_end и va_copy. Если доступ к переменным аргументам равен , вызываемая функция должна объявить объект (обычно , называемый ap в этом подпункте), имеющего тип va_list. Объект ap может быть передан в качестве аргумента другой функции; если это функция вызывает va_arg макроса с параметром ap, значение ap в вызывающей функции является неопределенным и должны быть передано va_end макро до какой-либо дальнейшей ссылки на ap.

Здесь вы пропускание va_list переменной varg функции vprintf, которая вызывает va_arg на него изнутри. Таким образом, после его возвращения вам больше не разрешается использовать varg. Вы должны позвонить va_end, прежде чем делать что-либо еще с ним. Вместо этого вы используете его в следующей итерации цикла без первого вызова va_end. Таким образом, вы сталкиваетесь с неопределенным поведением.

+0

В дополнение к этому; 'va_copy' может использоваться, если вы хотите обработать список дважды. Хотя то, что ОП пытается, возможно, невозможно сделать портативно. –

Смежные вопросы