`expected specifier-qualifier-list before ‘(’ token` inside a ternary operator

Inside the call function definition, I attempt to retrieve the variadic arguments passed to it in a loop using a ternary operator. The compilation stops with an expected specifier-qualifier-list before ‘(’ token error.

#define ARG_N 3

char *args_types[ARG_N] = {"int", "float", "char"};

void call(...) {
  va_list args;
  void *args_values[ARG_N];
  va_start(args, NULL);
  for (int i = 0; i < ARG_N; ++i) {
    char *arg;
    arg = args_types[i];
    args_values[i] = (void *)va_arg(args, (strcmp(arg, "int") ? int : strcmp(arg, "float") ? float : char));
  }
  va_end(args);
}

int main(void) {
  call(6, 55.33, 'c');
  return 0;
}

From my understanding, this error occurs when a structure is used uninitialized. What does it mean in this context?

  • Can you reduce your code to a minimal reproducible example?

    – 

  • I try, but it’s hard when I’m not sure which part affects the error.

    – 

  • 2

    expression ? type : type is not valid C syntax.

    – 

  • How is it not? It’s just a ternary operator. I been using the exact same operator to define cif: ffi_prep_cif(&cif, ABI, args_n, strcmp(ret_t, "int") == 0 ? &ffi_type_sint : strcmp(ret_t, "float") == 0 ? &ffi_type_float : &ffi_type_schar.

    – 

  • Okay, so the ternary operator can not return a type at run time, right? Is there a way to iterate over variadic function arguments?

    – 

You’re attempting to use the ternary operator to select a type. That is invalid syntax, as it can only be used to select an expression.

You’ll need to check for each individual type name, and based on that call va_arg with the appropriate type argument.

  for (int i = 0; i < ARG_N; ++i) {
    char *arg = args_types[i];
    if (!strcmp(arg, "int")) {
        args_values[i] = (void *)va_arg(args, int);
    } else if (!strcmp(arg, "float")) {
        args_values[i] = (void *)va_arg(args, float);
    } else {
        args_values[i] = (void *)va_arg(args, char);
    }
  }

Even after fixing this, you still have a problem because in one case you’re attempting to convert a float to a void *. Converting between a floating point type and a pointer type, event with a cast, is not allowed.

To fix this, you’ll probably need to dynamically allocate space for each value and assign the pointer to that dynamically allocated space:

  for (int i = 0; i < ARG_N; ++i) {
    char *arg = args_types[i];
    if (!strcmp(arg, "int")) {
        int *p = malloc(sizeof(int));
        *p = va_arg(args, int);
        args_values[i] = p;
    } else if (!strcmp(arg, "float")) {
        float *p = malloc(sizeof(float));
        *p = va_arg(args, float);
        args_values[i] = p;
    } else {
        char *p = malloc(sizeof(char));
        *p = va_arg(args, char);
        args_values[i] = p;
    }
  }

This also means you’ll need to know the types of these values elsewhere to cast the pointers to the proper types, and you’ll need to deallocate the space when you’re done with it.

Leave a Comment