Asked  6 Months ago    Answers:  5   Viewed   35 times

From the answers I got from this question, it appears that C++ inherited this requirement for conversion of short into int when performing arithmetic operations from C. May I pick your brains as to why this was introduced in C in the first place? Why not just do these operations as short?

For example (taken from dyp's suggestion in the comments):

short s = 1, t = 2 ;
auto  x = s + t ;

x will have type of int.

 Answers

98

If we look at the Rationale for International Standard—Programming Languages—C in section 6.3.1.8 Usual arithmetic conversions it says (emphasis mine going forward):

The rules in the Standard for these conversions are slight modifications of those in K&R: the modifications accommodate the added types and the value preserving rules. Explicit license was added to perform calculations in a “wider” type than absolutely necessary, since this can sometimes produce smaller and faster code, not to mention the correct answer more often. Calculations can also be performed in a “narrower” type by the as if rule so long as the same end result is obtained. Explicit casting can always be used to obtain a value in a desired type

Section 6.3.1.8 from the draft C99 standard covers the Usual arithmetic conversions which is applied to operands of arithmetic expressions for example section 6.5.6 Additive operators says:

If both operands have arithmetic type, the usual arithmetic conversions are performed on them.

We find similar text in section 6.5.5 Multiplicative operators as well. In the case of a short operand, first the integer promotions are applied from section 6.3.1.1 Boolean, characters, and integers which says:

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.

The discussion from section 6.3.1.1 of the Rationale or International Standard—Programming Languages—C on integer promotions is actually more interesting, I am going to selectively quote b/c it is too long to fully quote:

Implementations fell into two major camps which may be characterized as unsigned preserving and value preserving.

[...]

The unsigned preserving approach calls for promoting the two smaller unsigned types to unsigned int. This is a simple rule, and yields a type which is independent of execution environment.

The value preserving approach calls for promoting those types to signed int if that type can properly represent all the values of the original type, and otherwise for promoting those types to unsigned int. Thus, if the execution environment represents short as something smaller than int, unsigned short becomes int; otherwise it becomes unsigned int.

This can have some rather unexpected results in some cases as Inconsistent behaviour of implicit conversion between unsigned and bigger signed types demonstrates, there are plenty more examples like that. Although in most cases this results in the operations working as expected.

Tuesday, June 1, 2021
 
Fredy
answered 6 Months ago
58

Your understanding is correct. A string literal is really an array of char, and taking its value really yields a pointer to its first element. You can do this for any literal array (but without the syntax sugar that you have char arrays).

char *s = "String";        // right side is array of char
int *x = (int []){1, 2};  // right side is array of int

Similarly, the following are both incorrect.

char *s = 'S';
int *x = 1;

Note the difference between "String" and 'S'. The former is an array of char, but the latter is just an int.

However (as was first mentioned by Keith), string literals and literal arrays (more generally called compound literals) have different storage duration. In particular, a string literal always has static storage duration; but a compound literal has automatic or static storage duration, depending if it appears in a function or not. This means that if you take a pointer to a compound literal from within a function:

  • You can read and change change it until execution goes past the end of its block, and
  • You must not access it in any way after execution goes past the end of its block. Contrary, with string literals, you can read them after that, because they have static storage.

In this respect, taking a pointer to a literal array is very similar to just declaring an array (except, for example, sizeof()):

int x[] = {1, 2};
Thursday, July 29, 2021
 
NewPHP
answered 4 Months ago
44

Let's walk through your code:

short a = -5;

a = -5, which fits into a short. So far so easy.

unsigned short b = -5u;

-5u means apply the unary - operator to the constant 5u. 5u is (unsigned int) 5, and the unary - does no promotion, so you end up with 4294967291 which is 2^32-5. (Update: I got this bit wrong in my original answer; see a test script which shows this version is correct here http://codepad.org/hjooaQFW)

Now when putting that in b, it is truncated to an unsigned short (2 bytes, usually), so b = 65531, which is 2^16-5.

if( a == b )

In this line, a and b are both promoted to ints so that the comparison can happen correctly. If they were promoted to shorts, b would potentially wrap around. If they were promoted to unsigned shorts, a would potentially wrap around.

So it's like saying if( (int) a == (int) b ). And a = -5, so (int) a = -5, and b = 65531, so (int) b = 65531, because ints are bigger than shorts.

Wednesday, August 4, 2021
 
fhonics
answered 4 Months ago
19

chars are automatically promoted to integers in C expressions

Yes, they are. C99 section 6.3.1.8, Usual arithmetic conversions:

Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions:

  • First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose corresponding real type is long double.
  • Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.
  • Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose corresponding real type is float.62)
  • Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:
    • If both operands have the same type, then no further conversion is needed.
    • Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
    • Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
    • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
    • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

Integer promotions are described on Section 6.3.1.1.2:

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 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, 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 unchanges by the integer promotions.

The rank of a char is less than or equal to that of an int, so char is included in here.

(As a footnote, it is mentioned that integer promotions are only applied as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, - and ~, and to both operands of the shift operators).

As mentioned in the comments, integer promotion is also performed on function-call arguments.

Saturday, November 13, 2021
 
Arbalest
answered 2 Weeks ago
88

Well, consider this, derived from your example:

DateTime? myDate;
if (myDate != null)
{
    String runDate = DateTime.Now.ToString();
}
else
{
    DateTime runDate = DateTime.Now.AddDays(1);
}

string foo = runDate.ToString();

Following your proposal, the type of runDate (when foo is assigned) is unknown at compile-time, it could either be a string or a DateTime. This is not allowed in a statically-typed language.

Wednesday, November 17, 2021
 
user3284707
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share