1
usigned int x=1;
signed int y = -1;
double z = y * x * 0.25;

I'm using Microsoft Visual Studio 10 C++ compiler. Why z don't have -0.25 value? As I saw from disassembly, it makes an signed int multiply (imul), places the result from edx on the stack, and extends it with 0!, as it would be an unsigned int. After that it multiplies it using FP instructions.

.............
imul        edx,dword ptr [ecx]  
mov         dword ptr [ebp-98h],edx  
mov         dword ptr [ebp-94h],0
fild        dword ptr [ebp-98h]  
fmul        qword ptr [__real@3fd0000000000000 (1402FB8h)]  
fstp        qword ptr [z]

Why the result of multiply of signed * unsigned is interpreted as unsigned?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
asu
  • 539
  • 6
  • 15
  • Where do you see the zero extension? `[ebp-94h]` is not related to the result of the multiplication, `fild` takes a `dword` not a `qword`. – Daniel May 25 '12 at 09:04
  • There are very specific integral promotion rules where different integral types participate in a binary operation. My guess is that somewhere there, it would be precised what the correct behavior is, but honestly it's a mess... – Matthieu M. May 25 '12 at 09:05
  • Yeah that's right, blame the compiler. – ta.speot.is May 25 '12 at 09:10
  • 4
    As a rule of thumb: if you don't have vast experience of C/C++ and believe you have found a compiler bug, it means that there is a bug in your own code. This is especially true if the bug is related to implicit type promotions. – Lundin May 25 '12 at 09:11
  • As you say you are using the C++ compiler can we drop the C tag from this question? – CB Bailey May 25 '12 at 09:17
  • Check this link also "Signed to unsigned conversion in C - is it always safe?" - http://stackoverflow.com/questions/50605/signed-to-unsigned-conversion-in-c-is-it-always-safe. There is another "bug" to report - http://codepad.org/yPhYCMFO – SChepurin May 25 '12 at 09:40

3 Answers3

7

The expression y * x * 0.25 associates as (y * x) * 0.25 in both C and C++.

When multiplying an unsigned int and a signed int, both operands are converted to unsigned int and the results is also an unsigned int due to the integer conversion rules for arithmetic expressions in both C and C++ so the result of y * x will be UINT_MAX - 1 in both C and C++.

Your example doesn't exhibit a compiler bug whether you are compiling your example as C or C++.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • If it's not a compiler bug, then to me it looks even worse - a C++ specifications deficiency, or better saying "specifications bug", as mathematically speaking when you multiply a negative and positive numbers, the result is certainly a negative one, so why confuse engineers with unnatural rules? – asu May 09 '17 at 07:44
5

This is actually according to the spec. C++11, 5.9:

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

[...]

Otherwise, the integral promotions (4.5) shall be performed on both operands. Then the following rules shall be applied to the promoted operands:

[...]

  • Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

Here the two operands in y * x are signed and unsigned int, which have an equal integer conversion rank; so y ends up being converted to unsigned.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • No integral promotions are done in this specific case though. – Lundin May 25 '12 at 09:08
  • @Lundin: All *applicable* integral promotions are done. It's just that none are applicable in this case. IMHO the wording is not that bad. – Jon May 25 '12 at 09:11
  • I just wondered why you cited that part, as it will probably just confuse the OP. – Lundin May 25 '12 at 09:12
  • @Lundin: Because it's the part that says "the following rules shall be applied" :) – Jon May 25 '12 at 09:13
3

This is described in the [expr] section of the standard:

....

Otherwise, the integral promotions (4.5) shall be performed on both operands. Then the following rules shall be applied to the promoted operands:

— If both operands have the same type, 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 shall be converted to the type of the operand with greater rank.

— Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.

The expression is evaluated left to right and so y * x is calculated first. This has two integral types of the same rank, one operand signed and the other unsigned. Hence the signed value is converted to an unsigned value, as described in the final paragraph of the standards extract.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490