7

Consider the following code snippet:

#include <stdio.h> #include <stdarg.h> void display(int num, ...) { char c; int j; va_list ptr; va_start(ptr,num); for (j= 1; j <= num; j++){ c = va_arg(ptr, char); printf("%c", c); } va_end(ptr); } int main() { display(4, 'A', 'a', 'b', 'c'); return 0; } 

The program gives runtime error because vararg automatically promotes char to int, and i should have used int in this case.

What are all types are permitted when I use vararg, how to know which type to use and avoid such runtime errors.

9
  • 2
    Hehe, GCC says, "warning: ‘char’ is promoted to ‘int’ when passed through ‘...’". Nice. Commented Aug 16, 2011 at 20:55
  • 2
    In display(4, 'A', 'a', 'b', 'c'); there are 5 ints; not 1 int and 4 chars as you seem to believe :) Commented Aug 16, 2011 at 20:57
  • 1
    @Kerrek: it says that for the expression va_arg(ptr, char), not the call to the display function -- where there are no chars :) Commented Aug 16, 2011 at 21:02
  • 2
    @pmg: Ah, indeed -- that's one of the changes from C to C++: in C char literals are integers... I never knew you couldn't use chars variadically. wchar_t also doesn't work, and neither do char16_t or char32_t (they're all promoted to unsigned int). Commented Aug 16, 2011 at 21:05
  • This probably depends on the compiler / machine word length. You could even redefine va_arg to take account of this. Commented Aug 16, 2011 at 21:09

3 Answers 3

9

another case that the others forgot to mention are pointer types, critical is NULL in particular. Since this could expand to 0 or (void*)0 (or some other weird things) you will not know if the compiler puts an int or a void* in the list. Since these can have different width, this can lead to annoying bugs.

Sign up to request clarification or add additional context in comments.

1 Comment

Yep, that's always a subtle source of bugs. GCC is nice and expands NULL to __nullptr instead of 0, so you won't run into that bug with GCC, but other compilers are not so nice. The C standard only requires that NULL expand to an "implementation-defined null pointer constant", which is "an integer constant expression with the value 0, or such an expression cast to type void*.
6

You can use any standard type with va_arg except char, signed char, unsigned char, short, unsigned short, _Bool, and float. It's possible that an implementation defines additional nonstandard types that also have integer conversion rank lower than int, or likewise nonstandard small floating-point types, but you would not need to be aware of these unless you intend to use them, so for practical purposes the list I gave is complete.

Comments

1

While using va_arg the char is promoted to int. There are other types(the list given by @R..) which are promoted.

so in order to read it as a char you have to do typecast.

char c = (char) va_arg(ap, int); 

For a complete list, please see the 'Default conversions' section in:

http://en.cppreference.com/w/cpp/language/variadic_arguments

Comments