Стандартное приведение C к возвращаемому значению va_arg - PullRequest
2 голосов
/ 13 декабря 2011

Я занимаюсь разработкой программы на C, и я был озадачен этим предупреждением. Я хочу получить аргументы из списка, используя va_arg.

args[i] = (int) va_arg(argptr, int); 

или

args[i] = (char) va_arg(argptr, char);

проблема с этим предупреждением:

... void *' differs in levels of indirection from 'int'...

то же самое для случая с символом. Любое объяснение этому?

код:

void test_function(va_list argptr, int (*callback)(),
                   int ret_typel)
{
  int i ;
  int arg_typel;
  int no_moreb = TRUE;
  void *args[MAX_FUNCTION_ARGS];
  for (i=0; no_moreb; i++) {
    arg_typel = (int)va_arg(argptr, int);
    switch(arg_typel) {
    case F_INT:
      args[i] = (int) va_arg(argptr, int);
      break;
    case F_CHAR:
      args[i] = (char) va_arg(argptr, char);
      break;
    default:
      no_moreb = FALSE;
      i--;
      break;
    }
  }
}

Ответы [ 4 ]

10 голосов
/ 13 декабря 2011

Подробное описание использования va_arg().

Вы не можете использовать:

va_arg(argptr, char);

без вызова неопределенного поведения (что плохо !),Переменные аргументы функции varargs проходят повышение: float передается как double, а char, unsigned char, signed char, short, unsigned short повышается до int или unsigned (int)как требуется.Следовательно, вы никогда не сможете получить char напрямую с помощью va_arg;Вы можете указать только продвигаемые типы.Вам нужно было бы написать:

char c = (char) va_arg(argptr, int);
float f = (float) va_arg(argptr, double);

На этот раз приведение происходит в результате выполнения задания;говорить, что это происходит с приведением, не является строго необходимым, но не причиняет вреда (хотя я, вероятно, не стал бы писать приведение в своем собственном коде).

3 голосов
/ 13 декабря 2011

Проблема в том, что args[] - это массив void *. Вы не можете назначить int или float на void * (это не имеет никакого смысла). Вы можете обойти это, используя кастинг, но это не очень хорошая идея.

Если вы хотите хранить разные типы в одной переменной, рассмотрите объединение:

typedef union
{
    char  c;
    int   i;
    float f;
} MyUnion;

MyUnion args[MAX_FUNCTION_ARGS];

args[i].c = va_arg(argptr, char);
args[i].i = va_arg(argptr, int);
args[i].f = va_arg(argptr, float);

UPDATE Как правильно указывает Джонатан Леффлер в своем ответе, va_arg(argptr, char) и va_arg(argptr, float) не должны использоваться из-за продвижений по умолчанию для функций с переменным числом.

3 голосов
/ 13 декабря 2011

Массив args - это массив void *. Вы назначаете ему простые целые числа, по этой причине вы получаете ошибку.

0 голосов
/ 13 декабря 2011

Вам передают указатель void, и вы приводите указатель как int или char. Вам нужно разыменовать указатель void и затем привести его или сначала к типу (int *) или (char *).

...