简体   繁体   中英

How can I identify an integer promotion and a demotion in C?

I am learning C, and integer promotion and the term demotion is new to me. I have read in the C Standard (C17) about the C type conversions and the integer promotion, but I don't know how to identify an integer promotion, and I don't know anything about demotion.

For example, if I have these lines of code:

...
unsigned char x;
int y;
long int z;
int aux; //Auxiliary variable

x = 'c';
y = 1;
z = 2;

aux = x;
aux = y;
aux = z;

aux = x + y; //ZX
aux = y + z;
...

Where do I have integer promotion? Because from what I know, in the line of code commented with ZX , I have integer promotion, but only in that line, but I'm not sure; can you clarify it for me?

And can you give me examples of when demotion exists? Because the C standard does not clarify.

Definitely not my specialty, but let me try:

unsigned char x;
int y;
long int z;
int aux; //Auxiliar variable

x='c';
y=1;
z=2;    // Very subtle promotion here. 2 is an int, and is promoted to long int to fill z.

aux=x;  // Value of x, which is a char, is PROMOTED to int, to fill aux
aux=y;  // Both left and right sides are int, no promotion/demotion
aux=z;  // Z is a long int, is demoted to fill aux.

aux=x+y; // x(char) is PROMOTED for addition, to match other operand y(int)
aux=y+z; // y(int) is promoted to match longer type z(long int). The result(long int) is then demoted to match assignment aux.

I try not to over-rely on promotion rules when programming.

Integer promotion is a formal C term, but there exists no formal or even informal term called "demotion". Please check Implicit type promotion rules to learn about integer conversion rank, integer promotion and the usual arithmetic conversions.

The closest thing to demotion is "conversion during assignment", which can go from a larger type to a smaller or vice versa. This happens during assignment, in case the types of the operands differ (6.5.16.1):

In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.

As for how the actual conversions are carried out, see C17 6.3.1.3.


Regarding where you have integer promotions/implicit conversions in your code:

  • x = 'c'; Conversion during assignment, from the type of 'c' which is int , into unsigned char .

  • z = 2; Conversion during assignment, from the type of 2 which is int , into long .

  • aux = x; Conversion during assignment, from unsigned char to int .

  • aux = z; Conversion during assignment, from long to int .

    Conversions to signed types involves implementation-defined behavior, so it can be a possible bug if the larger value cannot fit in the smaller type.

  • aux = x + y; The usual arithmetic conversions, including integer promotion of x to int .

  • aux = y + z; The usual arithmetic conversions, turning y into long . Then conversion during assignment, converting back to int . Again, possible bug here.

(Some subtle stuff in the last example: in case y + z would result in a value that would overflow an int but not a long , that overflow doesn't actually happen here, because of the long conversion before addition. There would be a value loss upon conversion back to int but merely implementation-defined behavior and not undefined behavior overflow.)

The term demotion is not defined in the C Standard, it is only used once in the C17 Standard in the Annex J - Portability issues , which is informative only, not a normative part of the Standard. The phrase is not a definition, it just hints that demotion may happen when converting a value from one floating point type to another, presumably with a smaller domain:

Annex J
(informative)
Portability issues
1 This annex collects some information about portability that appears in this International Standard.

J.1 Unspecified behavior
[...]
J.2 Undefined behavior
The behavior is undefined in the following circumstances:
[...]
— Demotion of one real floating type to another produces a value outside the range that can be represented (6.3.1.5).

The word is not used in the linked section:

6.3.1.5 Real floating types
1 When a value of real floating type is converted to a real floating type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined. Results of some implicit conversions may be represented in greater range and precision than that required by the new type (see 6.3.1.8 and 6.8.6.4).

As stated in the annex, which is only informative, demotion happens for example when storing a double value to a float variable where its value cannot be represented by the float type. A typical case is found in a classic programming test:

float amount = 0.10;  // implicit conversion from double to float

There is no such as "demotion" of integers in C, but there are promotions. I believe you're confusing promotion and demotion with conversion .

An integer promotion occurs when an integer type smaller than int is used in an expression, where in most cases it will be promoted to either int or unsigned int . This is spelled out in section 6.3.1.1p2 of the C standard :

The following may be used in an expression wherever an int or unsigned int may 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.
  • A bit-field of type _Bool , int , signed int , or unsigned int .

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int ; otherwise, it is converted to an unsigned int . These are called the integer promotions . All other types are unchanged by the integer promotions.

This differs from a conversion , which occurs when any type changes to another type, whether the new type is larger or smaller than the original type.

Now applying this to your sample code:

x = 'c';

The assignment operator converts the right operand to the type of the left operand. Character constants have type int , so the assignment performs a conversion from int to unsigned char

y = 1;

Decimal integer constants with no suffix have type int , so no conversion or promotion here.

z = 2;

This assignment performs a conversion from int to long int .

aux = x;

This assignment performs a conversion from unsigned char to int .

aux = y;

Both sides have the same type, so no conversion.

aux = z;

This assignment performs a conversion from long int to int .

aux = x + y; //ZX

Looking at the + operator first, the left operand x is first promoted to int . Both operands now have type int , so no other conversions, and the result of x + y has type int . For the assignment, both sides have the same type so no conversion is applied

aux = y + z;

Looking at the + operator first, there is no promotion because both operands are at least as large as int . Because the left operand is an int and the right operand is a long int , the left operand is converted to long int and the result of y + z has type long int . This result is then converted to int for assignment to aux .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM