Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: функция с переменным числом аргументов
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
andrvisht
написал функцию для передачи переменного числа аргументов
Код
#include <stdarg.h>
void foo(unsigned char a, ...);
unsigned char A[5];
void foo(unsigned char a, ...)
{
char i;
  va_list arg_ptr;
  va_start(arg_ptr, a);
  for(i = 0; i < a; ++i)
    A[i]=va_arg(arg_ptr, unsigned char);
  va_end(arg_ptr);
}

void main(void)
{
  unsigned char b = '4', c = 'A';
  foo (5,23,b,32,c);
}

т.е. заполнение массива указанным числом аргументов, результат её работы получил следующий
A[] = {0x17, 0x00, 0x34, 0x00, 0x20}
как видно компилятор приводит мои аргументы к int. Для передачи числа 23 или 32 это еще можно понять, но как быть с явно указанными b и c ?

Попробовал данный код в Image Craft - результат тот-же, а вот Code Vision поступил честно (?)
и передал все параметры b и c как char.

Далее читаю help от IAR и узнаю что аргументом не может быть any integer type that changes when promoted естественно возник интерес к слову promoted и поиск по help дал следующее

Argument promotion occurs when the type of the function fails to provide any information about an argument. Promotion occurs if the function declaration is not a function prototype or if the argument is one of the unnamed arguments in a varying number of arguments. In this instance, the argument must be an rvalue expression.

на основании перевода (возможно неправильного) стало понятно что должна существовать возможность указания типа аргумента для неименованых аргументов в функции с переменным их числом, но как это сделать ... ?
PS: в книгах по С все приводимые примеры относятся к типу int sad.gif
zltigo
Цитата(&-rey @ May 23 2006, 09:09) *
т.е. заполнение массива указанным числом аргументов, результат её работы получил следующий
A[] = {0x17, 0x00, 0x34, 0x00, 0x20}

Точно уверены??? Cамое разумное объяснение, что-то Вы распечатали неправильно!
Ибо все абсолютно прозрачно...

Цитата
как видно компилятор приводит мои аргументы к int. Для передачи числа 23 или 32 это еще можно понять, но как быть с явно указанными b и c ?

Он их 'приводит' к размеру элемента в стеке и по другому быть НЕ МОЖЕТ и запихивает к стек.
По любому - передается _обезличенная_ информация.
За то, чем считать извлеченное из стека отвечает va_arg, которому Вы уже _указываете_ чем
считать извлеченное из стека. Следующий элемент извлекается из стека.
Абсолютно невороятный эффект, либо какая-то заморочка на AVR архитектуре мне не ведомая....

P.S.
А размер первым аргументом совсем незачем передавать - лишнее!
andrvisht
Цитата(zltigo @ May 23 2006, 10:31) *
Точно уверены??? Cамое разумное объяснение, что-то Вы распечатали неправильно!
Ибо все абсолютно прозрачно...

абсолютно точно.
число 23 в hex соответственно 0x17 если его хранить как int то младшие идут первыми, т.е.
0x17, 0x00
Цитата
Он их 'приводит' к размеру элемента в стеке и по другому быть НЕ МОЖЕТ и запихивает к стек.
По любому - передается _обезличенная_ информация.
За то, чем считать извлеченное из стека отвечает va_arg, которому Вы уже _указываете_ чем
считать извлеченное из стека. Следующий элемент извлекается из стека.

Это я понимаю, но ведь размер стека 8 бит а это char, кроме того я это смотрел в asm листинге, и IAR действительно заталкивает в стек int т.е. в макросах va_xxx ошибок нет, сам компилятор делает гадость sad.gif
Цитата
Абсолютно невороятный эффект, либо какая-то заморочка на AVR архитектуре мне не ведомая....
P.S.
А размер первым аргументом совсем незачем передавать - лишнее!


код приведен только для простоты обьяснения проблемы. А может это заморочка самого С ?
zltigo
Хорошо, а если вызвать foo() по прототипу foo( uchar, uchar, uchar, uchar, uchar ),
то все отрабатывает?
andrvisht
Цитата(zltigo @ May 23 2006, 11:02) *
Хорошо, а если вызвать foo() по прототипу foo( uchar, uchar, uchar, uchar, uchar ),
то все отрабатывает?

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

PS: конечно можно обойтись и другими методами, но интересен сам факт, чтобы знать стоит ли применять такие подходы в дальнейшем, или забыть о существовании оной.
zltigo
Цитата(&-rey @ May 23 2006, 11:31) *
да, так все нормально,
...
PS: конечно можно обойтись и другими методами, но интересен сам факт, чтобы знать стоит ли применять такие подходы в дальнейшем, или забыть о существовании оной.

Тогда конкретная ошибка компилятора?/макроса?. В принципе можете
- не использовать макросы
- написать альтернативные с учетом фокуса
- и самая простая заплатка - извлекать из стека int вместо char

Это стоит применять - удобно, кроме того, это фирменная 'C' фишка для обеспечения которой
делася обратный порядок аргументов в стеке. А Вы 'не применять' :-)
andrvisht
Цитата(zltigo @ May 23 2006, 11:53) *
Тогда конкретная ошибка компилятора?/макроса?. В принципе можете
- не использовать макросы
- написать альтернативные с учетом фокуса
- и самая простая заплатка - извлекать из стека int вместо char

ну да, если int извлекать тогда все впорядке конечно. Компилятор ведь int туда и ложит.
но хочется же экономии smile.gif а переписка макросов не даст экономии ввиду возникновения проблемы на этапе компилятора, да еще и своих ошибок добавлю ...
Цитата
Это стоит применять - удобно, кроме того, это фирменная 'C' фишка для обеспечения которой
делася обратный порядок аргументов в стеке. А Вы 'не применять' :-)

Да наверное я погорячился, на С перешел где-то с пол-года назад поэтому пока нет четкого представления что для чего удобно пользовать, вот и прорабатываю варианты испоьзования по мере необходимости.
И все таки есть сомнение что это глюк, или на других компиляторах IAR (под другие процы) все нормально ?
zltigo
Цитата(&-rey @ May 23 2006, 12:27) *
И все таки есть сомнение что это глюк, или на других компиляторах IAR (под другие процы) все нормально ?

Я даже проверять у себя на ARM не буду :-) ибо не предстваляю, как нужно извратиться, дабы сие
неправильно работало на процессоре с размерностью стека равной int - сразу отвечаю - работает.
А дабы не быть совсем уж голословным - использую переменное число аргументов лет двадцать, часто, платформы разные (но не менее 16bit), компиляторы еще более разные. Непониманий не возникало.

А в случае 8bit стека и 16bit int открываются просторы для невзаимоувязки :-( что и имеет место быть во всей красе.....

Цитата
а вот Code Vision поступил честно (?)
и передал все параметры b и c как char.

Т.е. Именно в стек поместил 8bit, или извлекал 16bit вместо 8??
andrvisht
Цитата(zltigo @ May 23 2006, 12:38) *
А в случае 8bit стека и 16bit int открываются просторы для невзаимоувязки :-( что и имеет место быть во всей красе.....

Да наверное вот тут он и приводит к int чтоб не нарушать общих правил, вот в книге Страуструпа тоже есть упоминание о приведении char к int а float к duble.
Вероятно Code Vision всего лишь исключение из правил, а жаль. Спасибо за поддержку.

Code Vision помещал в стек 8 бит, и извлекал соответственно char. т.е. оказался экономнее.
_Bill
Цитата(&-rey @ May 23 2006, 09:09) *
написал функцию для передачи переменного числа аргументов
Код
#include <stdarg.h>
void foo(unsigned char a, ...);
unsigned char A[5];
void foo(unsigned char a, ...)
{
char i;
  va_list arg_ptr;
  va_start(arg_ptr, a);
  for(i = 0; i < a; ++i)
    A[i]=va_arg(arg_ptr, unsigned char);
  va_end(arg_ptr);
}

void main(void)
{
  unsigned char b = '4', c = 'A';
  foo (5,23,b,32,c);
}

т.е. заполнение массива указанным числом аргументов, результат её работы получил следующий
A[] = {0x17, 0x00, 0x34, 0x00, 0x20}
как видно компилятор приводит мои аргументы к int. Для передачи числа 23 или 32 это еще можно понять, но как быть с явно указанными b и c ?

Видимо, тут вся проблема в оптимизации. Компилятор подставляет в аргументы функции не значения переменных b и c, а константы, которыми эти переменные проинициализированы. А поскольку константы всегда имеют тип int, то и получается то, что получилось. В общем, надо посмотреть сгенерированный код.
andrvisht
Цитата(_Bill @ May 23 2006, 14:38) *
Видимо, тут вся проблема в оптимизации. Компилятор подставляет в аргументы функции не значения переменных b и c, а константы, которыми эти переменные проинициализированы. А поскольку константы всегда имеют тип int, то и получается то, что получилось. В общем, надо посмотреть сгенерированный код.

от оптимизации это не зависит, и даже обьявление b и c как глобальных переменных со спецификатором volatile которое могло бы устранить такое недоразумение (имеется ввиду подставление константы вместо переменной) не помогло sad.gif
а код собственно сгенерить не сложно, вот он:
Код
main:
    00004C   9100 00D3        LDS     R16,c
    000050   E010             LDI     R17,0x00
    000052   931A             ST      -Y,R17
    000054   930A             ST      -Y,R16
    000056   E200             LDI     R16,0x20
    000058   E010             LDI     R17,0x00
    00005A   931A             ST      -Y,R17
    00005C   930A             ST      -Y,R16
    00005E   9100 00D2        LDS     R16,b
    000062   E010             LDI     R17,0x00
    000064   931A             ST      -Y,R17
    000066   930A             ST      -Y,R16
    000068   E107             LDI     R16,0x17
    00006A   E010             LDI     R17,0x00
    00006C   931A             ST      -Y,R17
    00006E   930A             ST      -Y,R16
    000070   E005             LDI     R16,0x05
    000072   DFD9             RCALL   foo
    000074   9628             ADIW    R28,8

явно видно что компилятор приводит все к int
вопрос в том как указать IAR что данные параметры будут char хотя не исключено, что это стандарт, и изменение его IAR не делает, что вообщем то правильно. Но так ли это ? хочется ясности.
zltigo
Цитата(_Bill @ May 23 2006, 14:38) *
Видимо, тут вся проблема в оптимизации.

Вы бы хоть дали себе труд прочитать все предыдущее, прежде, чем чего-то про "оптимизацию".....
_Bill
Цитата(&-rey @ May 23 2006, 15:04) *
явно видно что компилятор приводит все к int
вопрос в том как указать IAR что данные параметры будут char хотя не исключено, что это стандарт, и изменение его IAR не делает, что вообщем то правильно. Но так ли это ? хочется ясности.

Теперь все понятно. Специально прочитал в Help от Borland по этим функциям. Там сказано, что проверка типов аргументов в списке не производится. Видимо, нужно принять за аксиому, что тип аргументов int и писать функцию в соответсвием с этим.
andrvisht
Цитата(_Bill @ May 23 2006, 15:38) *
Видимо, нужно принять за аксиому, что тип аргументов int и писать функцию в соответсвием с этим.

вот и у меня сложилось такое же мнение.
GetSmart
Скажите, господа. Сам-то я знаю не весь синтаксис языка си. Так вот, если мне требуется процедура с переменным кол-вом параметров, в частности первый int, а остальные могут быть и int, и float, ну и long. В количестве всего от 2 до 5 параметров. То как мне объявить эту процедуру (пример) и как внутри читать параметры?
И желательно без этого: {va_list, va_start, va_arg,va_end}.
zltigo
Цитата(GetSmart @ Aug 1 2006, 01:41) *
Так вот, если мне требуется процедура с переменным кол-вом параметров...
....
И желательно без этого: {va_list, va_start, va_arg,va_end}.

Все абсолютно так-же как и вышеизложенном примере.
va_xxxx бояться не надо, это простейшие макросы или inline,
они просто предназначены для универсального описания.
Посмотрите на них и все станет ясным.
IgorKossak
Цитата(GetSmart @ Aug 1 2006, 01:41) *
Скажите, господа. Сам-то я знаю не весь синтаксис языка си. Так вот, если мне требуется процедура с переменным кол-вом параметров, в частности первый int, а остальные могут быть и int, и float, ну и long. В количестве всего от 2 до 5 параметров. То как мне объявить эту процедуру (пример) и как внутри читать параметры?
И желательно без этого: {va_list, va_start, va_arg,va_end}.

Информация о типах аргументов если они разные обычно передаётся в виде указателя на форматную строку (см. в качестве примера описание printf() и ключи форматной строки).
А вот без этого: {va_list, va_start, va_arg,va_end} ну никак нельзя.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.