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.
CodePudding user response:
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.
CodePudding user response:
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
orunsigned 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
, orunsigned 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 anunsigned 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
.
CodePudding user response:
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 "lvalue conversion during assignment", which can go from a larger type to a smaller or vice versa. Lvalue conversion being specified as (C17 6.3.2.1):
...an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. If the lvalue has qualified type, the value has the unqualified version of the type of the lvalue;
This happens for example during assignment, in case two types differ (6.5.16.1):
The type of an assignment expression is the type the left operand would have after lvalue conversion. ...
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.
For example
const int x = 5;
short y = x;
The const
qualifier is dropped during lvalue conversion and the const int
operand gets converted to type short
. The resulting type is short
and so sizeof(y=x)
will be 2.
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';
Lvalue conversion during assignment, from the type of'c'
which isint
, intounsigned char
.z = 2;
Lvalue conversion during assignment, from the type of2
which isint
, intolong
.aux = x;
Lvalue conversion during assignment, fromunsigned char
toint
.aux = z;
Lvalue conversion during assignment, fromlong
toint
.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 ofx
toint
.aux = y z;
The usual arithmetic conversions, turningy
intolong
. Then lvalue conversion during assignment, converting back toint
. 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.)
CodePudding user response:
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