5

In C 1999 note 86, speaking to 6.5.4 5 (my bold)

If the value of the expression is represented with greater precision or range than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is the same as the named type.

signed char a = -2;
unsigned char b = 1;
b = (short)a + (short)b;

b = (short)a + (short)b;. This is an example of

If the value of the expression is represented with greater precision or range than required by the type named by the cast (6.3.1.8),

Because if there isn't cast, a and b both are promoted to the int, which is greater precision or range than short which is the type named by the cast (suppose that short is 16 bit and int is 32 bit).

Then, in this case, the latter sentence

then the cast specifies a conversion even if the type of the expression is the same as the named type.

I want to know how this affects b = (short)a + (short)b;.

My thought was simple. Because (cast) has higher precedence than additive +, first a and b are casted by (short) and then two operands of + are converted by the usual arithmetic conversion. But the sentence "then the cast specifies a conversion even if the type of the expression is the same as the named type" confuses me.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
op ol
  • 705
  • 4
  • 11
  • 1
    The bold part would be a cast like `(double) 5.0`, where you cast the `double` value `5.0` to `double`. – Some programmer dude Nov 09 '20 at 08:25
  • @Someprogrammerdude But types of `5.0` and `double` are the same and have same precision and range. Do you mean only bold part fixed? – op ol Nov 09 '20 at 08:31
  • "... even if the type of the expression..." The expression in the case of `(double) 5.0` is `5.0`. "... is the same as the named type" The "named type" in `(double) 5.0` is `double`. So the cast `(double) 5.0` is a conversion from `double` to `double`. – Some programmer dude Nov 09 '20 at 08:39
  • Does `(double) 5.0` meet "If the value of the expression is ~ by the cast (6.3.1.8),"? I read usual arithmetic conversion. But I don't know the reason why 6.3.1.8 is specified. – op ol Nov 09 '20 at 08:44
  • @Someprogrammerdude Sorry for prior ambiguous question, I edited my post to make things clear. If you read my edited post, I will be thankful. – op ol Nov 09 '20 at 09:45
  • The text you quote for “C99 6.5.4 5” does not appear in the normative text. It is in note 86, which is non-normative. Please do not cite text in notes as if it were part of the main text. – Eric Postpischil Nov 09 '20 at 11:31

1 Answers1

3

This is about floating-point types. Integer types are not affected.

b = (short)a + (short)b;. This is an example of “If the value of the expression is represented with greater precision or range than required…”

No, the integer casts in that statement are not an example of that. C 2018 6.3.1.8 2 (same in C 1999) tells you it is about floating-point types:

The values of floating operands and of the results of floating expressions may be represented in greater range and precision than that required by the type; the types are not changed thereby.

What is happening here is that the C standard allows floating-point expressions to be computed with more range and precision than their nominal types, per C 2018 5.2.4.2.2 10:

Except for assignment and cast (which remove all extra range and precision), the values yielded by operators with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type…

(In C 1999, similar text appears at 5.4.2.2.2 7. The differences may have some significance but are not discussed here.)

This means that when you compute an expression with double, the compiler might, for example, generate code that uses long double. Or, when you compute an expression with float, the compiler might use double or long double. This makes it easier, for example, to implement C on a processor that has instructions for loading and storing single-precision (float) or double-precision (double) floating-point data but that has instructions for computing only double-precision floating-point, not for single-precision.

The note 86 you cited from C 1999 has been promoted to normative text in C 2018, as 6.5.4 6:

If the value of the expression is represented with greater range or precision than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is the same as the named type and removes any extra range and precision.

What this is telling you is that a cast must “remove” that extra range and precision. (This is unfortunate phrasing; it would be better to say that the value is rounded to a value representable in the named type using whatever rounding rule applies, commonly round-to-nearest ties-to-even.)

In C 2018 6.3.1.5 1 (not present in C 1999), about conversions between floating-point types, we see:

… 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).

So the situation is this: Floating-point expressions may be computed using extra range and precision. When there is an implicit conversion, such as when multiplying a float by a double (the usual arithmetic conversions convert the float to double), this extra range and precision may remain. However, when you have a cast in the source code, an “actual conversion” must be performed that converts the value with extra precision to a value representable in the nominal type. This is what it means to say that the cast specifies a conversion.

Although the conversion in assignment is implicit, assignments are also required to perform this conversion, as we are informed in 5.2.4.2.2 10, quoted above. That is also noted in note 65 to 6.3.1.8 2:

The cast and assignment operators are still required to remove extra range and precision.

It may be of note that a return statement performs an implicit conversion but is not required to remove extra range or precision.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks to point out my quotation is about floating types, I misunderstood things. The conclusion is 1. when two floating-point operands are operated, they are represented in greater range(may be long double or extended long double) 2. but when you use typecasting on one of the two, it is rounded to casted type's precision during calculation. Is this right? – op ol Nov 09 '20 at 12:39
  • And you said my quotation isn't in normative part. But the quotation I mentioned was in subclause of semantic of 6.5.4, not in the footnote. Is there a common documentation everyone discuss? My C99 draft is [this](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf) – op ol Nov 09 '20 at 12:45
  • 1
    @opol: That link is to a copy of draft n1256, which is a committee draft from September 7, 2007, leading up to the official standard in 2011. It is not the 1999 C standard, so it should not be cited as “C99.” You can cite it as draft n1256. Information about where to find official and unofficial drafts of the standard is in [this answer](https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents). – Eric Postpischil Nov 09 '20 at 13:25
  • 1
    @opol: Re “they are represented in greater range”: They **may be** represented with greater range and/or accuracy. It is up to the implementation. The header `` defines a macro `FLT_EVAL_METHOD` whose value may give further information: If it is 0, all floating-point expressions use the nominal type. If it is 1, `float` and `double` use `double`. If it is 2, all floating-point uses `long double`. If it is −1, the implementation is not saying what it does. It could use extra range and/or precision in some cases and not others. – Eric Postpischil Nov 09 '20 at 13:29