Reputation: 2318
I have the following piece of code which saves the result in 32 bit signed integer and 64 bit signed integer.
Using 32 bit signed integer results in a problem when I subtract 0 with 2147483647 (Max allowed value for signed 32 bit integer) so correct way should be using 64 bit signed integer and I should have to typecast unsigned 32 bit to signed 64 bit to get the desired answer. Is this the right way to do it?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
int main(void)
{
int32_t fig32;
int64_t fig64;
uint32_t peak_seq = 2480694779;
uint32_t pkt_seq = 2480694780;
uint32_t zero_seq = 0;
fig32 = peak_seq - pkt_seq;
fig64 = peak_seq - pkt_seq;
printf("\n 32 ans : %d, 64 ans is %ld\n", fig32, fig64);
fig32 = zero_seq - pkt_seq;
fig64 = zero_seq - pkt_seq;
printf("\n 32 ans : %d, 64 ans is %ld\n", fig32, fig64);
fig64 = (int64_t)peak_seq - (int64_t)pkt_seq;
printf("\n fix for (peak - pkt) 64 ans is %ld\n", fig64);
fig64 = (int64_t)zero_seq - (int64_t)pkt_seq;
printf("\n fix for (zero - pkt) 64 ans is %ld\n", fig64);
}
When I run this program, I get the following output
32 ans : -1, 64 ans is 4294967295
32 ans : 1814272516, 64 ans is 1814272516
fix for (peak - pkt) 64 ans is -1
fix for (zero - pkt) 64 ans is -2480694780
Upvotes: 4
Views: 1627
Reputation: 149095
Because C specs require that for unsigned int, the overflow use a modulus 2n (where n is the size of the int type). So peak_seq - pkt_seq
gives an unsigned int with the positive value FFFFFFFF
or 4294967295
. When you affect it to an int64_t or uint64_t variable, you get normally 4294967295
. When you affect if to a signed int variable, the result is implementation dependant, but for common implementation (complement to 2) it gives -1 => fig32 = -1
, fine.
You have 2 ways to obtain -1. One is implementation dependant, while the other is perfectly defined.
int64_t
is your best pickuint32_t
to a signed int32_t
it will work on current implementations and only then convert it to a int64_t
. First operation should give -1 (as int32_t
) that will be correctly converted to -1 as int64_t
Upvotes: 1
Reputation: 214475
First of all, in any C expression x = y + z;
the types used for the calculation of y + z
has nothing to do with the type of x
. The type used in any calculation depends on the types of the operands of the specific operator.
In your case, the type used to calculate peak_seq - pkt_seq
has no relation to where you happen to store the result. Since both operands are of type uint32_t
(and since int
is likely not larger than 32 bits on any machine), the operation is carried out on the uint32_t
type. The result is of type uint32_t
.
Since both operands are of the operation are of unsigned type, it underflows into 4294967295. Thus the result of peak_seq - pkt_seq
in this code is always (uint32_t)4294967295
, or if you will 0xFFFFFFFF.
In the first line why is the answer for 64 bit a 4294967295 and not -1 ?
When you try to store this result into a int32_t
, it gets converted according to implementation-defined behavior, in this case you'll get the two's complement version of 0xFFFFFFFF which is -1.
But when you try to restore the result in an int64_t
, it fits just fine and the value isn't changed.
Is typecasting all the unsigned 32 bit integers to signed 64 bit the only way to solve this problem?
If you want signed numbers, use signed numbers. The only reason why you would find the results of your code strange, is if you somehow incorrectly expect that two unsigned operands will give you a signed result.
As a side note, when printing int32_t
you should use printf("%" PRId, fig32)
and for int64_t
use PRId64
(inttypes.h).
Upvotes: 1