Better understanding of the type of progression of variational parameters in c

When the argument variable is called in c, integer parameters are incremented to int values, and floating-point parameters are incremented to double

Since the prototype does not specify types for optional arguments, argument arguments are added to the call to the variational function by optional argument values. This means that objects of type char or short int (whether signed or not) are advertised as int or unsigned int , depending on the situation; and that objects of type float promoted to type double . Thus, if the caller passes char as an optional argument, he is assigned an int , and the function can access it using va_arg (ap, int) .

int type must be 4 bytes on 32-bit machines and 8 bytes on 64-bit machines, right?
Therefore, I am wondering what to add when I pass a long long int variable variable, for example printf with the format %lld .
And once again it is interesting what to add when I pass the variable long double to printf with the format %Lf (regardless of whether on 32 or 64-bit machines).

[ Edited ]

on a 32 bit machine, I tried this:

 #include <stdio.h> int main(void) { printf("sizeof(int) %d\n", sizeof(int)); printf("sizeof(long int) %d\n", sizeof(long int)); printf("sizeof(long long int) %d\n", sizeof(long long int)); printf("%lld\n", 1LL<<33); printf("sizeof(float) %d\n", sizeof(float)); printf("sizeof(double) %d\n", sizeof(double)); printf("sizeof(long double) %d\n", sizeof(long double)); return 0; } 

Result:

 sizeof(int) 4 sizeof(long int) 4 sizeof(long long int) 8 8589934592 sizeof(float) 4 sizeof(double) 8 sizeof(long double) 12 

this makes me think that not all parameters are advanced to int , otherwise I would print 0 instead of 8589934592.

Perhaps only arguments smaller than int are promoted to int . And something like this could be for floating point types.

[ Edited ]

on a 64 bit machine, I run this:

 int main(void) { printf("sizeof(int) %lu\n", sizeof(int)); printf("sizeof(long) %lu\n", sizeof(long)); printf("sizeof(long long) %lu\n", sizeof(long long)); return 0; } 

and get

 sizeof(int) 4 sizeof(long) 8 sizeof(long long) 8 

if I understand the standard well, only char and short advance to int . Interestingly, what happens in a smaller architecture, such as a 16-bit or 8-bit MCU. I think the size of an int is architecture dependent, but I wonder if sizeof(int) be 1 on an 8-bit architecture. In this case, moving short to int may not be possible if you do not lose some bits.

+8
c floating-point c99 int printf
source share
3 answers

" int type must be 4 bytes on 32-bit machines and 8 bytes on 64-bit machines, right?" Not. According to the Standard, an int must have a width of at least 16 bits (§5.2.4.2.1) , but there are no additional conditions.

When you pass a long long int to printf() , it is not subject to integer shares (§6.3.1.1 2) :

The following expressions can be used in an expression: int or unsigned int can be used:

  • An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • Bit field of type _Bool, int, signed int or unsigned int.

If int can represent all values ​​of the original type (as limited in width for a bit field), the value is converted to int; otherwise, it will be converted to unsigned int. They are called whole promotions .58) All other types are not changed by the integer number of promotions .

If you pass a long double to printf() no conversion is performed (§6.5.2.2 6) :

If the expression denoting the called function is of a type that does not include the prototype, entire promotions are executed for each argument and arguments that are of type float are double. These are called default promotions.

Conversion specifiers matching the arguments in the printf() statement are not relevant to these promotions and conversions, except that there will be undefined behavior if the specifiers and types of their respective arguments do not match.

So, whole stocks are executed, and float converted to double s, but “No other conversions are performed implicitly” (§ 6.5.2.2 8) .

Addressing your editing to the question: "This makes me think that not all parameters are advanced to int ." Right. Only integer types with an integer of the conversion rank "less than or equal to the ranks of int and unsigned int " are subject to integral advertising. This is easier for floating point types; float up to double . It's all.

It may be worth noting that according to §6.2.5 10 there are three real types of floating point, float , double and long double . Values ​​that can be held by a float are a subset of the values ​​that can be held by a double , which, in turn, are a subset of the values ​​that can be held by a long double . Therefore, it is not possible to advance by long double types.

Further, according to §6.3.1.1 1 :

The rank of long long int must be greater than the rank of long int, which must be greater than the rank of int, which must be greater than the rank of short int, which must be greater than the rank of signed char.

Thus, it is not possible to advance long long int or long int to int or unsigned int .

As for your last concern that moving short to int may, in some implementations, be impossible without losing some bits, note that §6.2.5 8 ensures that int must contain short , since the conversion rank of int must be bigger than short rank:

For any two integer types with the same signature and different integer conversion rank (see 6.3.1.1), the range of values ​​of a type with a smaller integer conversion rank is a subrange of values ​​of another type.

+7
source share

The int type must be 4 bytes on 32-bit machines and 8 bytes on 64-bit machines, right?

Probably not. First of all, C gives no guarantees regarding the size of int , except that it must be at least 2 bytes (capable of at least holding a value of 2 ^ 16/2 - 1 = 32767). Nothing in C prevents an int from 8 bytes, but it is not very convenient.

Convention: All 8- and 16-bit computers use 16 bits of int . All other computers use 32 bits of int . This is the de facto standard. Any deviation from this agreement would be very exotic, although theoretically allowed by C.


So, I am wondering what to add when I pass a long long int to a variable variable such as printf with% lld.

You get a long long int. Advancement does not occur because the variable is not one of the small types mentioned. The format specifier used is not related to promotion rules.


it makes me think that not all parameters advance to int

Really. Only types covered by standard references. A formal definition of default promotions can be found in C11 6.5.2.2/6:

... entire promotions are executed for each argument, and arguments of type float are increased to two. These are called default promotions.

The value means that only small integer types are promoted (see integer promotion rule) and float . There are no other types.


Why do you think that your examples of printing different sizes of types have anything to do with promotions by default, I have no idea.

+3
source share

So I'm wondering what to add when I pass a long long int an argument variable, such as printf with the format %lld . And, again, I wonder what is added when passing a long double variable to printf using the %Lf format (regardless of whether on 32 or 64-bit machines).

Nothing happens since the long long int must be at least the same size as the int . Even in the most “pessimistic” scenario, where sizeof(long long int) == sizeof(int) , the argument is still passed “as is” (without any progress). The same goes for long double .

+1
source share

All Articles