7.16.1.1 2 describes va_arg as following (emphasis mine):

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, except for the following cases: one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;

one type is pointer to void and the other is a pointer to a character type.

Now to my understanding and it seems that 6.5.2.2 (function calls) does not contradict me, though I might be wrong, the default promotions are:

char to either int or unsigned (implementation specified)

to either or (implementation specified) signed char to int

to unsigned char to unsigned

to short to int

to unsigned short to unsigned

to float to double

This is all fine and dandy when you know the exact underlying types passed to the va_list (except for char , which AFAIK is impossible to retrieve portably because its signedness is implementation specified).

It gets more complicated when you're expecting types from <stdint.h> to be passed to your va_list .

int8_t and int16_t , deducting through logical limit observations, are guaranteed to be promoted or already be of type int . However it's very dubious to rely on my original "logical" limit observations, so I'm seeking your (and the standard's) confirmation on this deduction (I may be missing some corner cases I'm not even aware of).

and , deducting through logical limit observations, are guaranteed to be promoted or already be of type . However it's very dubious to rely on my original "logical" limit observations, so I'm seeking your (and the standard's) confirmation on this deduction (I may be missing some corner cases I'm not even aware of). the same holds for uint8_t and uint16_t , except the underlying type is unsigned

and , except the underlying type is int32_t may or may not be promoted to int . It may be larger than , smaller than or exactly the same as int . Same holds for uint32_t but for unsigned . How to portably retrieve int32_t and uint32_t passed to va_list ? In other words, how to determine if int32_t ( uint32_t ) has been promoted to int ( unsigned )? In yet other words, how to determine whether I should use va_arg(va, int) or va_arg(va, int32_t) to retrieve int32_t passed to the variadic function without invoking undefined behaviour on any platform?

promoted to . It may be larger than , smaller than or exactly the same as . Same holds for but for . In other words, In yet other words, I believe the same questions are valid for int64_t and uint64_t .

This is a theoretical (standard-only concerned) question, with a presumption that all exact-width types in <stdint.h> are present. I'm not interested in "what's true in practice" type of answers, because I believe I already know them.

EDIT