rajachan
rajachan

Reputation: 795

64bit arithmetic providing wrong output in 32-bit application

I couldn't understand why the below identical operations reports two different outputs. When my num is declared to be of negative value and I add the num to the baseAddr, I see my addr going past 32-bit range. On the other hand, if I declare num to a positive value and do a subtraction, I do see the right result. i.e my resulting output is reported accurately. Can someone please explain what is wrong with the below computation?

/* Architecture is powerpc. Program cross-compiled for powerpc. Gcc Version- 4.6.2 */
#include <stdio.h>
typedef unsigned long long u_int64;
typedef unsigned long u_int32;

int main() {
   u_int64 baseAddr = 0x8e008128;
   u_int32 num = -360;
   u_int64 addr = baseAddr + num;
   printf("\nAddr 1st step = 0x%llx\n", addr);

   /* Same operation, but slightly different */
   num = 360;
   addr = baseAddr - num;
   printf("\nAddr 2nd step = 0x%llx\n", addr);
   return 0;
}

/* Output:
Addr printed is 0x18e007fc0, but I need just 0x8e007fc0
/diagsk10copy/bin # ./e500GPR

Addr 1st step = 0x18e007fc0 //Wrong
Addr 2nd step = 0x8e007fc0
*/

Upvotes: 1

Views: 175

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726919

u_int32 is unsigned. The negative 360 that you assigned to it gets re-interpreted as a positive 32-bit number. When you add it to u_int64, the value gets extended with 32 zeros to match the size of the other operand. This is not what you wanted: since the number was negative, you need all ones in the upper half in order for the addition to produce the desired effect after the result of the addition is reduced modulo the number that is one greater than the largest value that can be represented by u_int64*.

If you declare the num as u_int64, the first and the second parts produce the expected number (demo on ideone).

u_int64 baseAddr = 0x8e008128;
u_int64 num = -360;
u_int64 addr = baseAddr + num; // Works!
printf("\nAddr 1st step = 0x%llx\n", addr);


* 6.2.5 (9) "A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.". Thanks, Daniel Fischer for finding the relevant portion of the standard!

Upvotes: 3

nneonneo
nneonneo

Reputation: 179592

u_int32 is an unsigned type; assigning -360 to it will cause integer overflow and result in num holding a very large positive value.

Upvotes: 4

Related Questions