C++ usual arithmetic conversions not converting

First, I'd like to point out that I did read some of the other answers with generally similar titles. However, those either refer to what I assume is an older version of the standard, or deal with promotions, not conversions.

I've been crawling through "C++ Crash Course", where the author states the following in the chapter exploring built-in operators:

If none of the floating-point promotion rules apply, you then check whether either argument is signed. If so, both operands become signed. Finally, as with the promotion rules for floating-point types, the size of the largest operand is used to promote the other operand: ...

If I read the standard correctly, this is not true, because, as per cppreference.com,

If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank

Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.

Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type

Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.

What confuses me even more is the fact that the following code:

printf("Size of int is %d bytes\n", sizeof(int));
printf("Size of short is %d bytes\n", sizeof(short));
printf("Size of long is %d bytes\n", sizeof(long));
printf("Size of long long is %d bytes\n", sizeof(long long));
unsigned int x = 4000000000;
signed int y = -1;
signed long z = x + y;
printf("x + y = %ld\n", z);

produces the following output:

Size of int is 4 bytes
Size of short is 2 bytes
Size of long is 8 bytes
Size of long long is 8 bytes
x + y = 3999999999

As I understand the standard, y should have been converted to unsigned int, leading to an incorrect result. The result is correct, which leads me to assume that no conversion happens in this case. Why? I would be grateful for any clafirication on this matter. Thank you.

(I would also appreciate someone telling me that I won't ever need this kind of arcane knowledge in real life, even if it's not true - just for the peace of mind.)

A conversion of a negative signed value to an unsigned leads into the binary complement value which corresponds to it. An addition of this unsigned value will lead into an overflow which then results just exactly in the same value as adding the negative value would do.

By the way: That's the trick how the processor does a subtraction (or am I wrong in these modern times?).

C Programming Tutorial for Beginners, Learn C the Hard Way: Practical Exercises on the Computational Subjects You Keep Avoiding (Like C) C programming is a general-purpose, procedural, imperative computer programming language developed in 1972 by Dennis M. Ritchie at the Bell Telephone Laboratories to develop the UNIX operating system. C is the most widely used computer language. It keeps fluctuating at number one scale of popularity

If I read the standard correctly, this is not true

You're correct. CCC is wrong.

As I understand the standard, y should have been converted to unsigned int,

It did.

The result is correct, which leads me to assume that no conversion happens in this case.

You assume wrong.

Since -1 is not representable unsigned number, it simply converts to the representable number that is representable and is congruent with - 1 modulo the number of representable values. When you add this to x, the result is larger than any representable value, so again result is the representable value that is congruent with the modulo. Because of the magic of how modular arithmetic works, you get the correct result.

"C" Programming Language: Brian Kernighan, This course will give you a full introduction into all of the core concepts in the C programming Duration: 3:46:13 Posted: Aug 15, 2018 = Simple assignment operator. Assigns values from right side operands to left side operand C = A + B will assign the value of A + B to C += Add AND assignment operator. It adds the right operand to the left operand and assign the result to the left operand. C += A is equivalent to C = C + A

C Tutorial, Computerphile. Computerphile. 1.75M subscribers. "C" is one of the most widely used Duration: 8:26 Posted: Aug 18, 2015 Programming Languages Development - C++ has been used extensively in developing new programming languages like C#, Java, JavaScript, Perl, UNIX’s C Shell, PHP and Python, and Verilog etc. Computation Programming - C++ is the best friends of scientists because of fast speed and computational efficiencies.

From the output of the first print statement from your code snippet it is evident that since the size of int is 4 bytes, the unsigned int values can range from 0 to 4,294,967,295. (2^32-1)

The declaration below is hence perfectly valid:

unsigned int x = 4000000000;

Remember here that declaring x as an unsigned integer gives itself twice the (+ve) range of a signed counterpart, but it falls in exactly the same range and hence conversions between them are possible.

signed int y = -1;
signed long z = x + y;
printf("x + y = %ld\n", z);

Hence for the rest of the code above, it doesn't matter here whether the operands of y and z are signed (+ve/-ve) or unsigned (+ve) because you are dealing with an unsigned integer in the first place, for which the signed integers will be converted to their corresponding unsigned integer versions by adding UINTMAX+1 to the signed version. Here UINTMAX stands for the largest unsigned value which is added with the smallest power of 2 (2^0=1). The end result would obviously be larger than values we can store, hence it is taken as modulo to collect the correct unsigned int.

However, if you were to convert x to signed instead:

signed int x = 4000000000;
int y = -1;
long z = x + y;
printf("x + y = %ld\n", z);

you would get what you might have expected:

x + y = -294967297

Learn C, C programming is a general-purpose, procedural, imperative computer programming language developed in 1972 by Dennis M. Ritchie at the Bell Telephone� C programming language assumes any non-zero and non-null values as true, and if it is either zero or null, then it is assumed as false value. Flow Diagram Example

I would also appreciate someone telling me that I won't ever need this kind of arcane knowledge in real life

There is one implicit promotion not addressed above that is a common cause of bugs:

unsigned short x = 0xffff;
unsigned short y = 0x0001;
if ((x + y) == 0)

The result of this is false because arithmetic operations are implicitly promoted to at least int.

Learn C Programming, learn-c.org is a free interactive C tutorial for people who want to learn C, fast. Microsoft C++, C, and Assembler documentation. Learn how to use C++, C, and assembly language to develop applications, services, and tools for your platforms and devices.

Cprogramming.com: Learn C and C++ Programming, C is a powerful general-purpose programming language. Our C tutorials will guide you to learn C programming one step at a time with the help of examples. Learn C# programming - for beginning developers, developers new to C#, and experienced C# / .NET developers

C Tutorial - Learn C, The best site for C and C++ programming. Popular, beginner-friendly C and C++ tutorials to help you become an expert! C-SPAN.org gives you access to C-SPAN's daily coverage of Washington and more than 200,000 hours of extensively indexed and archived C-SPAN video.

C Programming Language, C is a powerful systems programming language. Learn C with our popular C tutorial, which will take you from the very basics of C all the way through sophisticated�

Comments
  • @SergeBallesta: In this case I am not a careful programmer :-) I never saw that someone uses an explicit signed to unsigned conversion while using '+' operation. And this is because the standard is well defined to do all needed conversions/promotions.
  • Correct; the value of unsigned(-1) is UINT_MAX and unsigned overflow is well-defined as modulo 2^N.
  • Well, seems literally everyone agrees on the answer, so I'm going to mark this one as it was the first. I think I got the idea. Everyone, thank you once again. Stil not sure about the quote from CCC. Probably just a typo.