0

If we multiply two uint32_t types and they type inton this system has 63 value bits and one sign bit, then those values are converted to int( integer promotions ), multiplied, and converted back to uint32_t. The intermediate result cannot be represented by an int: 2^32-1 * 2^32-1 > 2^63-1, and triggers a signed integer overflow, causing undefined behavior.

Value of UINT32_MAX is 2^32-1, since uint32_t is guaranteed to have 32 value bits.

uint32_t a = UINT32_MAX ;
uint32_t b = UINT32_MAX ;
uint32_t c = a*b ;

Since platforms that have int the size of 64 bits are common, is my conclusion correct? The programmer expected that the result will wrap, since the type is unsigned, but the integer promotions will cause undefined behavior because of signed overflow.

reader
  • 496
  • 2
  • 15
  • @LPs Well, that is clearly not true. Unsigned cannot overflow. For example on a platform where uint32_t will not get converted to int and remains unsigned. But that was not my question. – reader May 13 '15 at 12:30
  • Is that first part even true? `UINT32_MAX * UINT32_MAX` would set the top bit (it's FFFFFFFE00000001) if you had 64bit ints, that isn't allowed is it? – harold May 13 '15 at 12:42
  • @harold Yes it would overflow the int even if int had 63 value bits. Well that makes is easier. – reader May 13 '15 at 12:45
  • So in that case, see this: http://stackoverflow.com/q/27001604/555045 – harold May 13 '15 at 12:51
  • @harold Yes, that is pretty sneaky behavior. – reader May 13 '15 at 12:52
  • I think you could get away with this by assigning `a` and `b` to `uint_fast32_t` before the multiplication. Type is unsigned, and would very likely be 64-bit on system where `int` is also 64-bit. – user694733 May 13 '15 at 12:55
  • @user694733 harold linked the duplicate. I guess the solutions is: don't multiply in C :-), unless you really have to and in that case use a library or something. – reader May 13 '15 at 12:56
  • It's not *that* bad, the linked question has a reasonable answer, and personally I'd just ignore this nonsense in practice (let's be honest here, the bignum library probably does too). It's a funny thing in theory though. – harold May 13 '15 at 13:09
  • @harold Those poor uint16_t can't catch a break. – reader May 13 '15 at 13:17
  • @harold: Unfortunately, some aggressive optimizers try to identify cases where calculations on `int` will overflow and eliminate code which would only be relevant in such cases. For example, given `uint32_t u`, `if (u < 0xFF000000) launch_missiles(); u*=u;`, some optimizers would recognize that because the program would engage in Undefined Behavior where the `if` condition was false, they may (and from their view, should) assume the condition will always be true. Unless or until the language standard is changed to rule that certain expressions involving `int` whose behavior would be... – supercat May 13 '15 at 16:43
  • ...the same in all *defined cases* as if they had been performed using a shorter unsigned type, must be yield the same result as if they had actually been performed using that shorter unsigned type, I no longer think it's safe to ignore such nonsense. BTW, I'm curious whether such a rule would impair the generation of optimal code outside of cases which are contrived to make phony "optimizations" useful. – supercat May 13 '15 at 16:46
  • @supercat that's still theory. Not even GCC pulls that stunt, though now that we've identified it it's probably only a matter of time, they are after all committed to the cause of language-lawyering first, providing a useful compiler second. – harold May 13 '15 at 16:53
  • @harold: I wish the people involved in the language-lawyering could work toward rules which would maximize *useful* optimization opportunities without requiring code to go to great lengths to avoid UB in portions of calculations whose results wouldn't otherwise matter. For example, if a processor with 64-bit registers doesn't have any 32-bit arithmetic operations (32-bit ADD, SUB, ADC, SBC, etc. would use opcode space which could be better utilized for other purposes), storing an `int32_t` whose address is never taken in a 64-bit register would be a useful optimization, but... – supercat May 13 '15 at 17:31
  • @supercat that isn't done? Doesn't sound too hard to do that transformation.. just insert some AND instructions in a couple of places (not everywhere, obviously) – harold May 13 '15 at 17:35
  • ...the Standard would presently not allow it unless the compiler includes code to sign-extend the lower portion of the register every time the result is promoted to a 64-bit integer whose upper bits would matter. More useful optimization opportunities would be authorized by such a rule than are authorized by the present lack of a rule making the result of any integer addition, multiplication, bitwise, left-shift, or unary operator be defined in all cases where it is cast or coerced to an unsigned type which would be promotable to `int` (applying coercion to the operands in turn). – supercat May 13 '15 at 17:36
  • @harold: My point is that compilers for such a machine are presently required to insert sign-extending instructions with `int32_t` math, but such instructions are in most cases, from a *practical* perspective, useless. IMHO, processor designers are unlikely to add modes which would make 32-bit math less efficient than 64-bit math unless or until languages change to minimize the number of cases where 32-bit math is actually required. Even if one wanted to have a language where value loss through overflow couldn't go undetected, it would be faster for a compiler on a 64-bit machine... – supercat May 13 '15 at 17:39
  • ...that was performing a bunch of operations on "32-bit" values, to perform intermediate computations on 64-bit values and only check for "overflow" when assigning the result back to a 32-bit variable, than to have to check the result of every individual operation for overflow. Freeing up an opcode bit that would otherwise be used for operand-size selection would enable processors to add many additional useful instructions, but I don't think that's likely to happen until languages can release most of their ties to 32-bit-ness. – supercat May 13 '15 at 17:42

1 Answers1

0

If you have such an obscure 64 bit int type with 32 only value bits, it still has the same precision as uint32_t. Given that 6.3.1.1 seems to only be concerned with precision when it comes to determining conversion rank, I don't think a 64 bit int, with the same number of value bits as a uint32_t, can be regarded to have a higher conversion rank. So no integer promotion should take place.

You will of course still get overflow no matter if there is integer promotion or not, because UINT32_MAX*2 can't fit in an uint32_t nor in your peculiar 64-bit-with-32-value-bits int.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • No int is defined to have 64 bits altogether and 31 padding bits. I think I have clearly stated that: *32 value bits, one sign bit, and 31 padding bits*. Integer with 32 value bits can represent all values of uint32_t, since uint32_t has exactly 32 value bits. – reader May 13 '15 at 12:38
  • @reader Ah, misread that part. Let me update the answer. – Lundin May 13 '15 at 12:39
  • Sorry I have edited the question substantially. – reader May 13 '15 at 12:51
  • @reader Good for you, thanks for wasting my time. Bye. – Lundin May 13 '15 at 12:52
  • What? Are you not trying to help people? Yes you didn't get points, but you did help someone. So only points matter to you? – reader May 13 '15 at 12:53
  • @reader I already updated the answer completely because I misread it the first time. Not going to change it yet again. I don't care about points, I care about not wasting time on questions that keep changing completely so that the present answers turn outdated and the whole post turns into something that doesn't make any sense. – Lundin May 13 '15 at 12:54
  • You can delete it so I can delete the question since I have found the duplicate. Thank you. – reader May 13 '15 at 12:58