va_arg глюки для чар - PullRequest
       10

va_arg глюки для чар

1 голос
/ 12 февраля 2020

Я пытаюсь использовать va_arg для получения следующего аргумента в функции. Он хорошо работает для всех типов (включая char *), но char:

void test1(char t,...) {
  va_list args;
  va_start(args, t);
  if(t=='c') Serial.println(va_arg(args, char));
  else if(t=='n') Serial.println(va_arg(args, int));
  va_end(args);  
}

Test:

int n = 42;
char c = '?';

test1('n', n); // prints 42
test1('c', c); // prints nothing!

Можете ли вы подтвердить или объяснить это? Код работает на Arduino Uno, 9600 бод.

Ответы [ 2 ]

6 голосов
/ 12 февраля 2020

Аргументы, меньшие int, переводятся в int перед передачей в функции c variadi, поэтому такие функции должны получать аргументы типа int.

1 голос
/ 12 февраля 2020

Функции Variadi c имеют специальное правило для неявного продвижения типов, известное как повышение аргументов по умолчанию .

C17 6.5.2.2/7

Многоточие в объявлении прототипа функции останавливает преобразование типа аргумента после последнего объявленного параметра. Повышение аргументов по умолчанию выполняется на конечных аргументах.

Ellipsis ...

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

C17 6.5.2.2/6

Если выражение, обозначающее вызываемую функцию, имеет тип, который не содержит прототип, выполняются целочисленные повышения для каждого аргумента и аргументы типа float повышаются до double. Они называются продвижениями аргументов по умолчанию .

. В вашем случае char считается целочисленным типом, а приведенное выше означает, что оно получит целое число повышенных при передаче в функцию variadi c.

Binary это означает, что ASCII ? = 0x3F повышается до int. AVR использует 16-битный порядок байтов, поэтому он сохраняется в памяти как 0x3F 0x00. Проблема не l ie.

Скорее, когда вы пытаетесь использовать va_arg для неправильного типа, вы вызываете неопределенное поведение. Это указано в документации для va_arg:

C17 7.16.1.1/2

Если фактического следующего аргумента нет или тип не совместим с типом фактический следующий аргумент (как продвигается в соответствии с продвижением аргумента по умолчанию), поведение не определено

Таким образом, единственное возможное решение - изменить код на if(t=='c') Serial.println(va_arg(args, int));.


Независимо от вашего вопроса, использование функций variadi c и stdio.h на 8-битном MCU - очень плохая практика. Эти функции не только опасны, они также потребляют много fla sh и оперативной памяти.

Кроме того, для встроенных систем всегда следует использовать stdint.h вместо типов по умолчанию C.

...