Search code examples
ctype-conversionexpressioninteger-promotion

How possibly can a unary +/- operator cause integral promotion in "-a" or "+a", 'a' being an arithmetic data type constant/variable?


This seemingly trivial line is taken from the C book my Mike Banahan & Brady (Section 2.8.8.2).

I can understand how implicit promotion comes into play in expressions like c=a+b depending on the types of the operands, but I am unable to grasp how and in which case the same can figure in something like -b, where b is any legitimate operand. Can you explain it and then give a proper example?

Extracted text follows:

The usual arithmetic conversions are applied to both of the operands of the binary forms of the operators. Only the integral promotions are performed on the operands of the unary forms of the operators.

Update:

Lest it goes unnoticed, here I am adding what I asked based on OUAH's answer in a comment– The book says 'Only the integral promotions are performed'...Does it mean that in an expression like x=-y, where 'x' is a long double and 'y' is a float, 'y' won't be promoted to long double if we explicitly use a unary operator? I know it would be, but asking it nevertheless to get a clearer idea about the "Only the integeral promotions..." part.

Update:

Can you explain with example how promotion comes into play for the following bit-wise operators? For the last three, should I assume that whenever those are used on a variable, it is promoted to integer type first? And what exactly does the "usual arithmetic conversions" mean for the first three? Can you give a small example? I don't want to post it as a separate question if it can be settled here.

enter image description here


Solution

  • For a unary arithmetic operator, the C standard says (in section 6.5.3.3) that

    The integer promotions are performed on the operand, and the result has the promoted type.

    It also defines the term, in section 6.3.1.1:

    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.

    (References are to the N1570 draft of the 2011 C standard.)

    I believe the rationale for this is that implementations are not required to support any arithmetic operations on types narrower than int (one "word"). Operands narrower than an int are converted to int, or to unsigned int, before they're operated on.

    For binary operators (those taking two operands), there's an additional requirement, that both operands must be of the same type. Typical CPUs might have instructions to add two 32-bit signed integers, or two 32-bit unsigned integers, or two 64-bit signed or unsigned integers, but none that will directly add, for example, a 32-bit signed integer and a 64-bit unsigned integer. To allow for this, we have the usual arithmetic conversions, described in section 6.3.1.8. These rules tell you, for example, what happens when you try to add an int to a double: the int operand is promoted, by conversion, to type double, and the addition adds the resulting two double operands.

    The shift operators don't require the usual arithmetic conversions, since there's no particular need for both operands to be of the same type. The left operand is a value to be operated on; the right operand specifies the number of bits to shift it.

    Does it mean that in an expression like x=-y, where x is a long double and y is a float, y won't be promoted to long double if we explicitly use a unary operator?

    Assignment causes the right operand to be converted to the type of the left operand. The expression -y is evaluated independently of the context in which it appears (this is true for most expressions). So the unary - is applied to its operand, which is of type float (the integer promotions don't affect that), yielding a result of type float. The assignment causes that float value to be converted to long double before being assigned to x.

    The title of your question asks how this can possibly happen. I'm not sure what that means. The conversion rules are specified in the language standard. Compilers follow those rules.