Integer Overflow - c

I have an unsigned long long that I use to track volume. The volume is incremented by another unsigned long long. Every 5 seconds I print this value out and when the value reaches the 32 bit unsigned maximum the printf gives me a negative value. The code snippet follows:
unsigned long long vol, vold;
char voltemp[10];
vold = 0;
Later...
while (TRUE) {
vol = atoi(voltemp);
vold += vol;
fprintf(fd2, "volume = %llu);
}
What am I doing wrong? This runs under RedHat 4 2.6.9-78.0.5.ELsmp gcc version 3.4.5

Since you say it prints a negative value, there must be something else wrong, apart from your use of atoi instead of strtoull. A %llu format specifier just doesn't print a negative value.
It strongly looks like the problem is the fprintf call. Check that you included stdio.h and that the argument list is indeed what is in the source code.

Well I can't really tell because your code has syntax errors, but here is a guess:
vol = atoi(voltemp);
atoi converts ascii to integer. You might want to try atol but that only gets it to a long, not a long long.
Your C standard library MIGHT have atoll.

You can't use atoi if the number can exceed the bounds of signed int.
EDIT: atoll (which is apparently standard), as suggested, is another good option. Just keep in mind that limits you to signed long long. Actually, the simplest option is strtoull, which is also standard.

Are you sure fprintf can take in a longlong as a parameter, rather than a pointer to it? It looks like it is converting your longlong to an int before passing it in.

I'd guess the problem is that printf is not handling %llu the way you think it is.
It's probably taking only 32 bits off the stack, not 64.
%llu is only standard since C99. maybe your compiler likes %LU better?

For clarification the fprintf statement was copied incorrectly (my mistake, sorry). The fprintf statement should actually read:
fprintf(fd2, "volume = %llu\n", vold);
Also, while admittedly sloppy the maximum length of the the array voltemp is 9 bytes (digits) which is well within the limits of a 32-bit integer.
When I pull this code out of the program it is part of and run it in a test program I get the result I would expect which is puzzling.

If voltemp is ever really big, you'll need to use strtoull, not atoi.

Related

Multiple Inputs in one scanf showing a miscellanous behaviour

I was trying a simple calculation using long data types. Addition of three numbers. But while I take inputs in one scanf function, it take takes intial two input as zero.
#include <stdio.h>
int main()
{
long x,y,z;
printf("Input x,y,x:\n");
scanf("%lld %lld %lld",&x,&y,&z);
printf("Result: %lld\n",x+y+z);
return 0;
}
The code works perfectly fine in online compiler but not in my vscode. I checked the version of C we are using the same.
I changed the code a little, i.e.,
scanf("%lld %lld %lld",&z,&y,&x);
and now it works perfectly fine.
Why? How can just the arrangement of variable solved the issue.
I did the initial code in int data type with %d format specifier, it worked perfectly fine but not the same with long and %lld.
Can anyone explain why this happened or what is the error.
Why does it works on online compiler but not my vs code.
I was expecting the sum of three numbers.
The %lld specifier expect the address of a long long. You instead passed in the address of a long. Using the wrong format specifier triggers undefined behavior.
What most likely happened, given that you're using VS Code and therefore most likely running on Windows, on that system a long is 4 bytes while a long long is 8 bytes. So when scanf attempts to read a value, it writes 8 bytes into the the pointer it's given instead of 4, writing past the end of a variable and most likely into another.
The online compiler you're using is probably using gcc which has an 8 byte long so it happens to work.
You should instead be using the %ld format specifier which expects the address of a long.
scanf("%ld %ld %ld",&x,&y,&z);
It's happening because you have used the wrong format specifier of long. Either declare the variables as long and use the format specifier as %ld or declare the variables as long long and use the format specifier as %lld

Different output with printf

I am trying to print the value of a particularly large value after reading it from the console. When I am trying to print it from two different ways, one directly after assigning, one with the return value from the strtol function, I get different output! Can someone please explain me why I am noticing two different outputs?
Input value is: 4294967290
Here is the code snippet.
long int test2 = strtol(argv[1], &string, 10);
printf("the strtol value is %ld\n", test2);
printf("the strtol function value is %ld\n", strtol(argv[1], &string, 10));
Output
the strtol value is -6
the strtol function value is 4294967290
You need to do two things:
Add the line #include <stdlib.h> at the beginning of your program. That will cause strtol to be declared. (You also need #include <stdio.h> in order to declare printf.)
Add -Wall to your compiler flags (if you are using gcc or clang). That will cause the compiler to tell you that you need to declare strtol, and it might even suggest which header to include.
What is going on is that you haven't declared strtol, with the result that the compiler assumes that it returns an int.
Since 4294967290 is 232-6, it is the 32-bit Two's-complement representation of -6. Because the compiler assumes that strtol returns an int, the code it produces only looks at the low-order 32 bits. Since you are assigning the value to a long, the compiler needs to emit code which sign-extends the int. In other words, it takes the low-order 32 bits as though they were a signed integer (which would be -6) and then widens that -6 to a long.
In the second call to printf, the return value of strtol is inserted in the printf argument list without conversion. You tell printf that the argument is a long (by using the l flag in %ld), and by luck the entire 64 bits are in the argument list, so printf reads them out as a long and prints the "correct" value.
Needless to say, all this is undefined behaviour, and the actual output you are seeing is in no way guaranteed; it just happens to work that way with your compiler on your architecture. On some other compiler or on some other architecture, things might have been completely different, including the bit-length of int and long. So the above explanation, although possibly interesting, is of no practical value. Had you simply included the correct header and thereby told the compiler the real return type of strtol, you would have gotten the output you expected.

Bizarre math error when doing a basic check in C

For a simple program, the assignment was to create a program that accepts a ten digit phone number, and then reads it back to the user.
There were to be controls to ensure that:
The first digit is not 0.
That the number entered is ten numbers.
The error check seemed simple; I thought using a while loop to ensure that the range of the number was between 1000000000 and 9999999999 would work out, and according to independent calculations, it seems it should.
while ((MDN - valueCheck < 0) || (MDN > 9999999999)) {
printf("Entered number is not ten digits. Please re-enter.\n");
scanf("%d", &MDN);
}
Both MDN and valueCheck are long long type variables (so that the range can go past 2,147,483,647; IIRC long long was 64-bit), but they seem to still be listed as 32-bit integers, as entering 2147483647 comes out just fine (or any lower phone number works as well), but entering 2,147,483,648 (or anything above) causes it to be displayed as -2147483647.
Related to the above, entering a higher number, not only does the value wrap around the range of the 32-bit integer, but the phone number printed by the printf statement after the loop is always equal to the entered number minus twice the limit of a 32-bit integer.
Is there any simple way to make the program actually work in 64-bit numbers like I wanted it to? The algorithm seems solid, if I can make the math work properly.
Try scanf("%lld", &MDN); instead of scanf("%d", &MDN);
From man scanf:
ll (ell ell)
Indicates that the conversion will be one of dioux or n and the
next pointer is a pointer to a long long int (rather than int).
Q: Is there any simple way to make the program actually work in 64-bit numbers like I wanted it to?
A: Use int64_t and "%" SCNx64.
If you:
want 32-bit integers, use type int32_t.
want 64-bit integers, use type int64_t.
use int, the range is at least -32767 to +32767.
use long, the range is at least -2147483647 to +2147483647.
use long long, the range is at least -9223372036854775807 to +9223372036854775807.
With scanf() use the matching format specifier:
int "%d"
long "%ld"
long long "%lld"
int32_t "%" SCNx32
int64_t "%" SCNx64
You could've used this:
scanf("%lld", &MDN);
but there are issues with coding and approach itself (see below)
I would advise to stick to string-regexp input-validation approach instead.
Coding issue:
scanf() in a loop is vulnerable to unprocessed-input-buffer issue, e.g if user enters a text instead of a number - scanf() will fail, stdin won't be consumed and loop will continue eternally.
See "How to clear input buffer in C?" for details. Following change should address it:
while(!scanf("%lld", &MDN)) {
char c;
while(c=getchar()!='\n'&& c!=EOF);
}
Approach issue:
The approach itself is vulnerable to overflow and type-trimming issues.
For example: "-9999999999999999999" will pass all MDN validations (see below).
Also there could be compiler/specific issues while comparing long long (MDN)to an integer (0 or 9999999999 instead of 0LL or 9999999999LL).
Entered number is not ten digits. Please re-enter.
-9999999999999999999
"MDN" is -9223372036854775808
"MDN > 9999999999" is false
"MDN - valueCheck < 0" is false (!) because "MDN - valueCheck" is 9223372035854775808

atoi function in C not working properly (when exceeding a certain value)

Might someone explain why the atoi function doesn't work for nmubers with more than 9 digits?
For example:
When I enter: 123456789,
The program program returns: 123456789,
However,when I enter: 12345678901
the program returns: -519403114...
int main ()
{
int i;
char szinput [256];
printf ("Enter a Card Number:");
fgets(szinput,256,stdin);
i=atoi(szinput);
printf("%d\n",i);
getch();
return 0;
}
Don't use atoi(), or any of the atoi*() functions, if you care about error handling. These functions provide no way of detecting errors; neither atoi(99999999999999999999) nor atoi("foo") has any way to tell you that there was a problem. (I think that one or both of those cases actually has undefined behavior, but I'd have to check to be sure.)
The strto*() functions are a little tricky to use, but they can reliably tell you whether a string represents a valid number, whether it's in range, and what its value is. (You have to deal with errno to get full checking.)
If you just want an int value, you can use strtol() (which, after error checking, gives you a long result) and convert it to int after also checking that the result is in the representable range of int (see INT_MIN and INT_MAX in <limits.h>). strtoul() gives you an unsigned long result. strtoll() and strtoull() are for long long and unsigned long long respectively; they're new in C99, and your compiler implementation might not support them (though most non-Microsoft implementations probably do).
Because you are overflowing an int with such a large value.
Moreover, atoi is deprecated and thread-unsafe on many platforms, so you'd better ditch it in favour of strto(l|ll|ul|ull).
Consider using strtoull instead. Since unsigned long long is a 64-bit type on most modern platforms, you'll be able to convert a number as big as 2 ^ 64 (18446744073709551616).
To print an unsigned long long, use the %llu format specifier.
if you are writing win32 application then you can use windows implementation of atoi, for details check the below page.
http://msdn.microsoft.com/en-us/library/czcad93k%28v=vs.80%29.aspx

C int datatype and its variations

Greetings , and again today when i was experimenting on language C in C99 standard , i came across a problem which i cannot comprehend and need expert's help.
The Code:
#include <stdio.h>
int main(void)
{
int Fnum = 256; /* The First number to be printed out */
printf("The number %d in long long specifier is %lld\n" , Fnum , Fnum);
return 0;
}
The Question:
1.)This code prompted me an warning message when i try to run this code.
2.)But the strange thing is , when I try to change the specifier %lld to %hd or %ld,
the warning message were not shown during execution and the value printed out on the console is the correct digit 256 , everything also seems to be normal even if i try with
%u , %hu and also %lu.In short the warning message and the wrong printing of digit only happen when I use the variation of long long specifier.
3.)Why is this happening??I thought the memory size for long long is large enough to hold the value 256 , but why it cannot be used to print out the appropriate value??
The Warning Message :(For the above source code)
C:\Users\Sam\Documents\Pelles C Projects\Test1\Test.c(7): warning #2234: Argument 3 to 'printf' does not match the format string; expected 'long long int' but found 'int'.
Thanks for spending time reading my question.God bless.
You're passing the Fnum variable to printf, which is typed int, but it's expecting long long. This has very little to do with whether a long long can hold 256, just that the variable you chose is typed int.
If you just want to print 256, you can get a constant that's typed to unsigned long long as follows:
printf("The number %d in long long specifier is %lld\n" ,256 , 256ULL);
or cast:
printf("The number %d in long long specifier is %lld\n" , Fnum , (long long int)Fnum);
There are three things going on here.
printf takes a variable number of arguments. That means the compiler doesn't know what type the arguments (beyond the format string) are supposed to be. So it can't convert them to an appropriate type.
For historical reasons, however, integer types smaller than int are "promoted" to int when passed in a variable argument list.
You appear to be using Windows. On Windows, int and long are the same size, even when pointers are 64 bits wide (this is a willful violation of C89 on Microsoft's part - they actually forced the standard to be changed in C99 to make it "okay").
The upshot of all this is: The compiler is not allowed to convert your int to a long long just because you used %lld in the argument list. (It is allowed to warn you that you forgot the cast, because warnings are outside standard behavior.) With %lld, therefore, your program doesn't work. But if you use any other size specifier, printf winds up looking for an argument the same size as int and it works.
When dealing with a variadic function, the caller and callee need some way of agreeing the types of the variable arguments. In the case of printf, this is done via the format string. GCC is clever enough to read the format string itself and work out whether printf will interpret the arguments in the same way as they have been actually provided.
You can get away with slightly different types of arguments in some cases. For example, if you pass a short then it gets implicitly converted to an int. And when sizeof(int) == sizeof(long int) then there is also no distinction. But sizeof(int) != sizeof(long long int) so the parameter fails to match the format string in that case.
This is due to the way varargs work in C. Unlike a normal function, printf() can take any number of arguments. It is up to the programmer to tell printf() what to expect by providing a correct format string.
Internally, printf() uses the format specifiers to access the raw memory that corresponds to the input arguments. If you specify %lld, it will try to access a 64-bit chunk of memory (on Windows) and interpret what it finds as a long long int. However, you've only provided a 32-bit argument, so the result would be undefined (it will combine your 32-bit int with whatever random garbage happens to appear next on the stack).

Resources