Variadic functions come with an oddball special rule for implicit type promotion known as the default argument promotions.
C17 6.5.2.2/7
The ellipsis notation in a function prototype declarator causes
argument type conversion to stop after the last declared parameter. The default argument
promotions are performed on trailing arguments.
Ellipsis being ...
The default argument promotions are normally just used when using old style non-prototype functions. They are therefore defined as:
C17 6.5.2.2/6
If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float
are promoted to double
. These are called the default argument promotions.
In your case, char
counts as an integer type and the above means that it will get integer promoted when passed to a variadic function.
Binary this means that ASCII ?
= 0x3F gets promoted to int
. AVR uses 16 bit little endian so it gets stored as 0x3F 0x00 in memory. The problem does not lie there.
Rather, when you try to use va_arg
on the wrong type, you invoke undefined behavior. This is stated in the documentation for va_arg
:
C17 7.16.1.1/2
If there is no actual next argument, or if
type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined
So the only possible solution is to change the code to if(t=='c') Serial.println(va_arg(args, int));
.
Unrelated to your question, using variadic functions and stdio.h on a 8 bit MCU is very bad practice. Not only are these function dangerous, they will also consume lots of flash and RAM.
Also, for embedded systems, you should always use stdint.h
instead of the default types of C.