I'm trying to make use of errno
to detect if I've performed an operation that causes overflow. However, although I've written a function which deliberately overflows, errno == ERANGE
is false. What's going on here?
Here's the code:
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]) {
unsigned char c = 0;
int i;
for (i = 0; i< 300; i++) {
errno = 0;
c = c + 1;
if (errno == ERANGE) {// we have a range error
printf("Overflow. c = %u\n", c);
} else {
printf("No error. c = %u\n", c);
}
}
return 0;
}
I expected this to give an overflow error at the point where we added one to 255, but there is no error. Here's the (truncated) output:
No error. c = 245
No error. c = 246
No error. c = 247
No error. c = 248
No error. c = 249
No error. c = 250
No error. c = 251
No error. c = 252
No error. c = 253
No error. c = 254
No error. c = 255
No error. c = 0
No error. c = 1
No error. c = 2
No error. c = 3
No error. c = 4
No error. c = 5
No error. c = 6
No error. c = 7
No error. c = 8
No error. c = 9
Can someone explain why it doesn't detect the error, and how I might change it or otherwise make a function that can detect if my value has overflowed? Note: ultimately I want to be doing this with long int
s, so it's not possible to simply convert it to a larger data type.
EDIT:
I've since found some simple functions to detect overflow from addition and multiplication of integral data types, respectively. It doesn't cover all situations, but it covers a lot of them.
Multiplication:
int multOK(long x, long y)
/* Returns 1 if x and y can multiply without overflow, 0 otherwise */
{
long p = x*y;
return !x || p/x == y;
}
Signed addition:
int addOK(long x, long y)
/* Returns 1 if x and y can add without overflow, 0 otherwise */
{
long sum = x+y;
int neg_over = (x < 0) && (y < 0) && (sum >= 0);
int pos_over = (x >= 0) && (y >= 0) && (sum < 0);
return !neg_over && !pos_over;
}
Unsigned addition:
int unsignedAddOK(unsigned long x, unsigned long y)
/* Returns 1 if x and y can add without overflow, 0 otherwise */
{
unsigned long sum = x+y;
return sum > x && sum > y;
}
An integer overflow occurs when you attempt to store inside an integer variable a value that is larger than the maximum value the variable can hold. The C standard defines this situation as undefined behavior (meaning that anything might happen).
In general, a data type overflow error is when the data type used to store data was not large enough to hold the data. Furthermore, some data types can only store numbers up to a certain size. An overflow error will be produced, for example, if a data type is a single byte and the data to be stored is greater than 256.
But in a 64-bit build, the compiler upcasts the unsigned int to a signed 64-bit type, meaning there is no integer overflow and the expected path in the program is executed.
In general, when an unsigned int overflows, it rolls over to zero. So UINT_MAX + 5 rolls over and becomes 4. It would be the difference between the max uint value and the value of what would have been the overflow value.
Errno is not an processor-set variable, it is only used by system calls and some standard functions to repport errors.
I don't know any technique for detecting what you ask, exept from verifying if c < c + 1
on each loop iteration.
Edit : After some research, I found this wikipedia about status registers, which are CPU flags that indicates such errors.
From what I understand, errno
is set by functions. It wouldn't detect addition overflow errors unless you create your own function that does. You can test to see if the result is less than one of your operands.
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]) {
unsigned char c = 0, result = 0;
int i;
for (i = 0; i< 300; i++) {
result = c + 1;
if (result < c) {// we have a range error
printf("Overflow. c = %u\n", result);
} else {
c = result;
printf("No error. c = %u\n", c);
}
}
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With