Comparison between big numbers doesn't seem to work - c

The program I wrote takes two numbers and makes a division and a modulo operation.
The code is
#define ADDRESS_SPACE 4294967295
int main (int argc, char *argv[]) {
long int pagesize = atoi(argv[1]), virtaddr = atoi(argv[2]);
if (virtaddr >= ADDRESS_SPACE) {puts("Address is too large"); return 1;}
printf("%lu\n", virtaddr);
printf("%lu\n", ADDRESS_SPACE);
printf("Page = %lu\nOffset = %lu\n", virtaddr/pagesize, virtaddr%pagesize);
return 0;
}
And doing ./page 1024 9999999999999999999999999999999999999999999999 gives the following output
18446744073709551615
4294967295
Page = 0
Offset = 18446744073709551615
If virtaddr is bigger than ADDRESS_SPACE, why isn't the if statement working? I know there's an overflow, but printing the variables doesn't show any error and they are still numbers (the maximum value a long int can take).

Because atoi converts from ASCII to ints and not to long ints and also 9999999999999999999999999999999999999999999999 is far to big to be converted into an int.
Try using sscanf for the string conversion and also try a more reasonable number.

18446744073709551615 is the unsigned version of -1. virtaddr is signed but you displayed it as unsigned; of course -1 is going to be less than any valid positive number.

atoi returns INT_MAX when the number is out of range. Comparing a 32-bit int to 4294967295 is always false, because INT_MAX is roughly two times smaller. If you use strtoll instead of atoi, your solution will work, because the result will be in the range of long long. Alternatively, you could use INT_MAX instead of ADDRESS_SPACE.

Related

Range of Unsigned & Signed int

#include <stdio.h>
int main(int argc, char **args){
int d=4294967295;
unsigned e= -1;
printf("\n%u\n%d\n%d\n%u\n%lu\n",d,d,e,e,sizeof(int));
return 0;
}
Output:
4294967295
-1
-1
4294967295
4
Question is, if both signed and unsigned integers can be used to display all kinds of integers by just applying a suitable format string, what's the need for unsigned in the first place?
You are right in so far as (on machines using two's complement and having 32 bit ints) the 0xFFFFFFFF is displayed as -1 with %d, but as 4294967295 with %u.
But strictly speaking this is undefined behaviour.
But the real difference between signed and unsigned variables is in their arithmetic interpretation. The main differences are
with comparing: -1 < 0, but 0 < 4294967295.
with multiplication and division.
Unsigned can hold a larger positive value, and no negative value. Unsigned uses the leading bit as a part of the value, while the signed version uses the left-most-bit to identify if the number is positive or negative. Signed integers can hold both positive and negative numbers.

reverse number for max unsigned int

I try to write a program for reverse the user input number.
The user input range is from 0 < a < 4294967295,
here is EDITED code.
unsigned long int reverseNumber(unsigned long int num)
{
unsigned long int rev = 0;
while (num > 0)
{
rev = rev *10 + (num%10);
num = num/10;
}
return rev;
}
The problem is when I input 4294967295, it will output 1632727628.
Why? I have no idea why it happened.
How can I reverse the 4294967295.
I had changed it to unsigned long int, printf by using %lu, but still output 1632727628. Why?
The reverse of 4294967295 is 5927694924 which is greater than the range of unsigned int
In your system, unsigned int is 32-bit wide, hence the max value that an unsigned int can represent is 4294967295 i.e. 0xFFFFFFFF. That is why your result is overflowing and whatever remains in 32 bits is shown as output.
If you represent 5927694924 in hex, it is 0x16151724C which has extra 33rd bit 1, which is discarded and hence output is 0x6151724C which is 1632727628 in decimal.
To print it on screen you need a greater data type like unsigned long long or uint64_t or unsigned long (on 64-bit systems only), whatever your compiler supports for 64 bit integers.
The reverse of 4294967295 is 5927694924, which is greater than 4294967295, which is the greatest integer which can be stored on 32 bit.
The problem is when I input 4294967295, it will output 1632727628. Why?
unsigned int can store 2^32-1 max. The reverse of 4294967295 is 5927694924 which is much bigger than 2^32-1. Hence the out put is 1632727628. 1632727628 is in fact 5927694924 % 4294967296
To solve this you should have used unsigned long it. But again if the number is great than highest long it'll overflow again.

Overflow in C code

Can anyone explain to me why this code prints "error" ? This only appears for minimal value of integer.
int abs(int x) {
int result = 0;
if(x < 0)
result = -1*x;
else
result = x;
return result;
}
int main() {
printf("Testing abs... ");
if (abs(-2147483648) != 2147483648)
printf("error\n");
else
printf("success\n");
}
Because for a 32 bit integer signed integer, using two's complement, the largest number you can store is 2147483647.
The range is -2147483648 2147483647.
You must be careful - overflowing signed numbers is undefined behavior.
The maximal value of a 32 bit integer is 2,147,483,647.
put long instead of int. For bigger integers you will need long long. Google for the range that this types offer. Also for the comparison with a static number you must declare it like e.g. 8438328L
Because of the way integers are represented (2's complement), if your int is 32 bits, -2147483648 is its own negative.
After -2147483648 is returned by your abs(), it is probably being compared as a long, 64-bit integer. If the comparison were 32-bit, 2147483648 would be equivalent to -2147483648. Perhaps if you turn on all warnings for your compiler, it will complain?
The range of 32-bit signed integers is, as has been mentioned before -2147483648 (= -231) to 2147483647 (= 231 - 1). In your abs() function, you have thus overflow of a signed integer, which is undefined behaviour (citation of standard to be inserted). Therefore anything could happen, but what actually happens is very probably that the result just wraps around, producing -2147483648 again. However, you compare that to the integer literal 2147483648, which does not fit into a 32-bit signed integer, hence, since it has no (n)signedness suffix, that literal has the next type in the list
int
long int
long long int
which can represent its value (if any). On 64-bit systems that could be long int or long long int, the former is typically the case on Linux, the latter, as far as I know on Windows, on 32-bit systems it's almost certainly long long int.
Then the int value -2147483648 is promoted to long (long) int and the tested condition is
if (-2147483648L != 2147483648L) // or LL

Bitwise complement operator

Can you guys please explain the below program
int main()
{
int max = ~0;
printf("%d\n",max);
return 0;
}
AFAIK ~ will flip the bits. In this case i.e ~0 will set all the bits into 1. So max variable should contain MAX value but I am getting o/p as -1. So can anyone here please tell me why I am getting o/p as -1.
Why did you expect to obtain the "max value"? In 2's-complement signed representation all-1 bit pattern stands for -1. It is just the way it is.
Maximum value in 2's-complement signed representation is represented by 01111...1 bit pattern (i.e the first bit is 0). What you got is 1111...1, which is obviously negative since the very first bit - sign bit - is 1.
If you want an example where complemented zero produces a "max value", use unsigned representation
int main() {
unsigned max = ~0u;
printf("%u\n", max);
}
That is the correct output since you are using the int data type which is signed. You need to read about two's complement negative representation. All one bits is not the maximum negative value, it is -1 as your program outputs. Maximum negative signed value is most significant bit set and all the remaining bits zero, 0x80000000 in the 32-bit case. Maximum positive signed value is 0x7fffffff in the 32-bit case.
The above answers have already covered the reason behind ~0 having value -1.
If you are looking for max integer value, then you can include the limits.h library and use the constants declared in that library
INT_MAX gives you the maximum signed integer value.
UINT_MAX gives you the maximum unsigned integer value.
#include <stdio.h>
#include <limits.h>
int main()
{
printf( "Max signed int value: %d \n", INT_MAX);
printf("Max unsigned int value: %u \n", UINT_MAX );
return 0;
}
This question was a long time ago, but for posterity's sake:
It might help you to see it better if you print ~0 as both int and hex as follows:
printf("compliment of zero %d\n", (~0));
printf("compliment of zero 0x%x\n", (~0));
Output:
Compliment of zero -1
Compliment of zero 0xffffffff

Printing unsigned long long using %d

Why do I get -1 when I print the following?
unsigned long long int largestIntegerInC = 18446744073709551615LL;
printf ("largestIntegerInC = %d\n", largestIntegerInC);
I know I should use llu instead of d, but why do I get -1 instead of 18446744073709551615LL?
Is it because of overflow?
In C (99), LLONG_MAX, the maximum value of long long int type is guaranteed to be at least 9223372036854775807. The maximum value of an unsigned long long int is guaranteed to be at least 18446744073709551615, which is 264−1 (0xffffffffffffffff).
So, initialization should be:
unsigned long long int largestIntegerInC = 18446744073709551615ULL;
(Note the ULL.) Since largestIntegerInC is of type unsigned long long int, you should print it with the right format specifier, which is "%llu":
$ cat test.c
#include <stdio.h>
int main(void)
{
unsigned long long int largestIntegerInC = 18446744073709551615ULL;
/* good */
printf("%llu\n", largestIntegerInC);
/* bad */
printf("%d\n", largestIntegerInC);
return 0;
}
$ gcc -std=c99 -pedantic test.c
test.c: In function ‘main’:
test.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
The second printf() above is wrong, it can print anything. You are using "%d", which means printf() is expecting an int, but gets a unsigned long long int, which is (most likely) not the same size as int. The reason you are getting -1 as your output is due to (bad) luck, and the fact that on your machine, numbers are represented using two's complement representation.
To see how this can be bad, let's run the following program:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(int argc, char *argv[])
{
const char *fmt;
unsigned long long int x = ULLONG_MAX;
unsigned long long int y = 42;
int i = -1;
if (argc != 2) {
fprintf(stderr, "Need format string\n");
return EXIT_FAILURE;
}
fmt = argv[1];
printf(fmt, x, y, i);
putchar('\n');
return 0;
}
On my Macbook, running the program with "%d %d %d" gives me -1 -1 42, and on a Linux machine, the same program with the same format gives me -1 42 -1. Oops.
In fact, if you are trying to store the largest unsigned long long int number in your largestIntegerInC variable, you should include limits.h and use ULLONG_MAX. Or you should store assing -1 to your variable:
#include <limits.h>
#include <stdio.h>
int main(void)
{
unsigned long long int largestIntegerInC = ULLONG_MAX;
unsigned long long int next = -1;
if (next == largestIntegerInC) puts("OK");
return 0;
}
In the above program, both largestIntegerInC and next contain the largest possible value for unsigned long long int type.
It's because you're passing a number with all the bits set to 1. When interpreted as a two's complement signed number, that works out to -1. In this case, it's probably only looking at 32 of those one bits instead of all 64, but that doesn't make any real difference.
In two's complement arithmetic, the signed value -1 is the same as the largest unsigned value.
Consider the bit patterns for negative numbers in two's complement (I'm using 8 bit integers, but the pattern applies regardless of the size):
0 - 0x00
-1 - 0xFF
-2 - 0xFE
-3 - 0xFD
So, you can see that negative 1 has the bit pattern of all 1's which is also the bit pattern for the largest unsigned value.
You used a format for a signed 32-bit number, so you got -1. printf() can't tell internally how big the number you passed in is, so it just pulls the first 32 bits from the varargs list and uses them as the value to be printed out. Since you gave a signed format, it prints it that way, and 0xffffffff is the two's complement representation of -1.
You can (should) see why in compiler warning. If not, try to set the highest warning level. With VS I've got this warning: warning C4245: 'initializing' : conversion from '__int64' to 'unsigned __int64', signed/unsigned mismatch.
No, there is no overflow. It's because it isn't printing the entire value:
18446744073709551615 is the same as 0xFFFFFFFFFFFFFFFF. When printf %d processes that, it grabs only 32 bits (or 64 bits if it's a 64-bit CPU) for conversion, and those are the signed value -1.
If the printf conversion had been %u instead, it would show either 4294967295 (32 bits) or 18446744073709551615 (64 bits).
An overflow is when a value increases to the point where it won't fit in the storage allocated. In this case, the value is allocated just fine, but isn't being completely retrieved.

Resources