Mathematically, 0 / 0 is undefined. But, in C programming (especially gcc compiler gcc-7.3.0 on ubuntu), it produces the answer as 1. I would like to know the reason. Is it working by repeated subtraction? For, the same code, if I use n = 1 / n, I get a floating point exception. However, for gcc-5.3.0, it produces an error.
#include <stdio.h>
int main() {
int n = 5;
n = n - 5;
switch (n) {
case 0:
printf("n= %d", n);
n = n / n;
printf("n calc= %d", n);
break;
case 5:
printf("n=5");
break;
default:
printf("n=1");
break;
}
return 0;
}
Divide by zero is undefined behavior in C programming (C11 6.5.5 §6). Meaning that there is no predictable result, there is no telling what your program might do.
It isn't very meaningful to try reason about why you get one particular outcome of "anything might happen". It might print 1, it might print 42, it might print nothing at all. The program might crash and burn. If you run the program twice, you might get different outcomes. And so on.
As for why you won't get a compiler error, the compiler isn't able or obliged to find or diagnose run-time errors. Most cases of undefined behavior need to be avoided by the programmer.
Some good compilers may be able to give warnings if you use pure integer constant expressions such as int x = 0/0;, but again it is not the job of the compiler to find this bug. It is the programmer's job. Therefore you should make a habit of always checking if the right operand of / or % is zero before applying the operands.
Compilers are allowed to assume that the code does not invoke undefined behavior, and use that assumption while optimizing the code.
For any value, other than n==0 the expression n/n evaluates as 1. Since diving by zero is undefined behavior in C, the compiler can assume that this scenario never happens, i.e., it can assume that n!=0.
Since it may assume that, the compiler can replace the slow n/n with the cheap constant value of 1. This is probably what happens with the code in question.
Of course, the compiler is not required to make any such assumption, and might generate an actual division. Depending on the hardware that executes the code, a specific hardware signal (or exception) might be triggered in such a case of division by zero. I doubt that any reasonable compiler will emit division in this example for optimized code, because division is extremely slow, and according to the standard the constant 1 is good enough. However, it is still likely it will produce an actual division in debug mode.
Similar things happen when optimizing away other undefined behavior, such as int overflow:
void f(int x)
{
if (x > x + 1)
// executed only in case of overflow,
// which is undefined behavior,
// and hence likely optimized out.
overflow_error();
...
Don't rely on undefined behavior - it is not predictable.
As can be seen on Godbolt's compiler explorer, both gcc and clang optimize n / n for n integer to evaluate to 1 without any warning. gcc performs this optimisation even at -O0 whereas clang generates the division opcode for -O0 but the optimized alternative for -O1 and above.
0 / 0 has undefined behavior anyway, therefore any behavior for n / n is OK if n is zero, including evaluating to 1 without an observable side-effect.
If you insist, you could qualify n as volatile and the compiler might generate a division, as both gcc and clang do in this case, but as long as n is read twice, it does not have to.
Related
OS: Ubuntu 18.04
GCC: 7.5.0
I'm writing an expression generator to test my simple debugger, and want to filter the expressions with division by zero behavior. However i encounter a troubling problem.
As for the definite division by zero behavior akin to int c = 1/0, it will raise a signal so i can handle these cases by signal(). Nevertheless, in the case akin to int c = 1/0*0, cis equal 0 , and the program will never trap into the signal handler.
The test code as below.
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void ss(int sig){
printf("division by zero.\n");
exit(0);
}
int main(){
int c;
signal(SIGFPE, ss);
c = (1u/0u)*0u;
printf("%d\n", c);
}
Here is the result.
gcc -o divide_0 divide_0.c
divide_0.c: In function ‘main’:
divide_0.c:15:11: warning: division by zero [-Wdiv-by-zero]
c = (1u/0u)*0u;
^
0
How can i capture the warning in this case?
Forcing the compiler to execute a division by zero is actually hard:
First, as you have noted, the compiler may evaluate 1/0 at compile-time. To prevent it from knowing the divisor is zero, we can use a volatile object, as in volatile int zero = 0; c = 1/zero;. The volatile qualifier tells the compiler the object may be changed by means unknown to it, so it cannot assume it is zero and must get the value when the expression is being evaluated.
Multiplying by zero in (1u/0u)*0u is counterproductive, even after we change the divisor to zero. The compiler can reason that any defined result of (1u/zero)*0u is zero, and therefore it is allowed to use zero as the union of the defined results (zero) and the undefined results (whatever the compiler likes), so it can replace (1u/zero)*0u with zero, 0. That is, it must still evaluate zero because it is volatile, but then it is free to just produce zero as the result without doing the division.
The compiler does not have to use a division instruction to evaluate a division operator. I tested with Apple Clang 11, and it was evaluating 1u/zero with instructions equivalent to zero == 1 ? 1 : 0;. In other words, it just did a compare and a set, not a division, presumably because compare and set is faster. When I changed this to 13u/zero, then the compiler used a divide instruction. I expect your best bet for getting a divide instruction would be to use volatile int unknown = 0; unknown = unknown/unknown;. Even then, a compiler would be allowed by the C standard to perform the division using any instructions it wanted, not a divide. But I presume compilers will generally generate a divide instruction in this case.
Then this code will execute a division at run-time. Whether that causes a signal and what happens with that signal depends on your computing platform.
Division by zero is not guaranteed to generate a signal.
Whenever your expression evaluator performs a division, it needs to check if the divisor is 0, and if so perform an appropriate action.
I assume that the compiler somehow just removes the division. It is allowed to do that. So instead try this code:
int main(int argc, char **argv){
int c;
int d = argc - 1;
signal(SIGFPE, ss);
c = 1u/d;
printf("%d\n", c);
}
Call it without arguments. The trick here is that the compiler cannot know how many arguments you will give the program, so it cannot optimize it away. Well, not as easily anyway.
The compiler itself complains about this since it can tell that your code is faulty and unsafe. However, you can try to use -Wno-div-by-zero argument for gcc at your own risk.
Integer division by zero is undefined and should result floating point exception and this is what happens why I write the following code
int j = 0 ;
int x = 1 / j;
In this case the program just crashes with FPE, but if I won't use variable and will go with literal values like this int x = 1 / 0; the the program doesn't crash, but just assigns some random value to x ! I tried to detect if int x = 1 / 0; really causes a crash by adding custom SIGFPE handler, but as I thought it is never invoked during literal zero division, but it does when I store 0 in a variable first. So, it seems that the literal zero division never actually crashes the program( I mean the division itself never happens), so does the compiler(GCC in my case) performs any tricks(e.g. substituting 0 with random number) in this case? or I misunderstood something ?
Why integer division by zero doesn't crash the program compiled with gcc?
Well, I think the answer would be: because it can. It can crash. It can not crash.
or I misunderstood something ?
From C11 6.5.5p5 (emphasis mine :p) :
The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.
The behavior is not defined. It is not defined what should happen. It can "crash". It can not crash. It can spawn nasal demons. The program can do anything.
You should write only programs that you know how will they behave. If you want your program to "crash", call abort().
so does the compiler(GCC in my case) performs any tricks(e.g. substituting 0 with random number) in this case?
The only way to know is to inspect the generated assembly code. You could use https://godbolt.org/
Since the expression contains division by zero constant, gcc could handle the issue at compile time.
If the division by variable valued 0, the compiler will give the responsibility to the exception handler because the evaluation is unpredictable.
In reference to C11 draft, section 3.4.3 and C11 draft, section H.2.2, I'm looking for "C" implementations that implement behaviour other than modulo arithmetic for signed integers.
Specifically, I am looking for instances where this is the default behaviour, possibly due to the underlying machine architecture.
Here's a code sample and terminal session that illustrates modulo arithmetic behaviour for signed integers:
overflow.c:
#include <stdio.h>
#include <limits.h>
int main(int argc, char *argv[])
{
int a, b;
printf ( "INT_MAX = %d\n", INT_MAX );
if ( argc == 2 && sscanf(argv[1], "%d,%d", &a, &b) == 2 ) {
int c = a + b;
printf ( "%d + %d = %d\n", a, b, c );
}
return 0;
}
Terminal session:
$ ./overflow 2000000000,2000000000
INT_MAX = 2147483647
2000000000 + 2000000000 = -294967296
Even with a "familiar" compiler like gcc, on a "familiar" platform like x86, signed integer overflow can do something other than the "obvious" twos-complement wraparound behavior.
One amusing (or possibly horrifying) example is the following (see on godbolt):
#include <stdio.h>
int main(void) {
for (int i = 0; i >= 0; i += 1000000000) {
printf("%d\n", i);
}
printf("done\n");
return 0;
}
Naively, you would expect this to output
0
1000000000
2000000000
done
And with gcc -O0 you would be right. But with gcc -O2 you get
0
1000000000
2000000000
-1294967296
-294967296
705032704
...
continuing indefinitely. The arithmetic is twos-complement wraparound, all right, but something seems to have gone wrong with the comparison in the loop condition.
In fact, if you look at the assembly output, you'll see that gcc has omitted the comparison entirely, and made the loop unconditionally infinite. It is able to deduce that if there were no overflow, the loop could never terminate, and since signed integer overflow is undefined behavior, it is free to have the loop not terminate in that case either. The simplest and "most efficient" legal code is therefore to never terminate at all, since that avoids an "unnecessary" comparison and conditional jump.
You might consider this either cool or perverse, depending on your point of view.
(For extra credit: look at what icc -O2 does and try to explain it.)
On many platforms, requiring that a compiler perform precise integer-size truncation would cause many constructs to run less efficiently than would be possible if they were allowed to use looser truncation semantics. For example, given int muldiv(int x, ind y) { return x*y/60; }, a compiler that was allowed to use loose integer semantics could replace muldiv(x,240); with x<<2, but one which was required to use precise semantics would need to actually perform the multiplication and division. Such optimizations are useful, and generally won't pose problems if casting operators are used in cases where programs need mod-reduced arithmetic, and compilers process a cast to a particular size as implying truncation to that size.
Even when using unsigned values, the presence of a cast in (uint32_t)(uint32a-uint32b) > uint32c will make the programmer's intention clearer, and would be necessary to ensure that code will operate the same on systems with 64-bit int as on those with 32-bit int, so if one wants to test for integer wraparound, even on a compiler that would define the behavior, I would regard (int)(x+someUnsignedChar) < x as superior to `x+someUnsignedChar < x because the cast would let a human reader know the code was deliberately treating values as something other than normal mathematical integers.
The big problem is that some compilers are prone to generate code which behaves nonsensically in case of integer overflow. Even a construct like unsigned mul_mod_65536(unsigned short x, unsigned short y) { return (x*y) & 0xFFFFu; } which the authors of the Standard expected commonplace implementations to process as in a way indistinguishable from unsigned math, will sometimes cause gcc to generate nonsensical code in cases where x would exceed INT_MAX/y.
I am learning to code in C and need to get more familiar with overflow and dealing with large numbers. I need help dealing with the below code.
This isn't my desired output as when I do the calculations on my own, the negative numbers are incorrect. I know it has to do with the larger numbers I'm dealing with. How do I go about approaching this problem? I'm not to sure where to start?
Thanks!
int main() {
unsigned A = 1103624256;
unsigned B = 11254;
unsigned X = 1;
unsigned max_unsigned = (long)(UINT_MAX);
X = ((A*X)+B)%max_unsigned;
printf("X1 =\t%d\n", X);
X = ((A*X)+B)% max_unsigned;
printf("X2 =\t%d\n",X);
X = ((A*X)+B)%max_unsigned;
printf("X3 =\t%d\n", X);
X = ((A*X)+B)% max_unsigned;
printf("X4 =\t%d\n",X);
return 0;
}
my output is:
X1 = 1103635510
X2 = 823626102
X3 = -473507466
X4 = -1793402506
Program ended with exit code: 0
Unsigned Int uses quite often 32 bits. That means, the biggest representable number is 4294967296. This is then max_unsigned in your code.
Your first calculation X = ((A*X)+B)%max_unsigned is therefore 1103624256*1+11254%4294967296=1103635510, which is the result, you are seeing.
In your second calculation the expression A*X is then too big to fit into 32 bits.
That means, your code is illegal, because you do an illegal calculation. This is not covered by the C++ language standard. For example see here: https://en.cppreference.com/w/cpp/language/operator_arithmetic :
When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined.
That really means, that anything can happen. The program could behave on Mondays as you expect and on Tuesdays not. The program may crash. Your computer may crash. Your result may be incorrect. The behaviour is just not part of the language specification for C. And therefore the answer to your question must end here. That is the reason why for two years there is not even one answer to the question.
It may be the case that on certain platforms and certain compilers it is possible to predict the behaviour. And you may want to look at the Assembler code to see what happens. But all this is then outside the scope of the C language and therefore not of general interest. C is not a specification language for creating Assembler code. C has rules that must be followed. Otherwise you are not in the scope of C.
It would also not be very professional to speculate more, because in a professional environment you are normally paid to follow rules. And that includes the rules of the programming language.
If you are really interested to see what happens, you have to show the Assembler code and make it a question about Assembler programming. But there is no guarantee that your compiler always produces the same Assembler code for such illegal things. The compiler only guarantees you a predictable result if you follow the rules of the programming language and have no overflows.
I'm working on a homework assignment and am probably psyching myself out about this thing a little too much, so I am just seeking some input. Here's the basic code:
for(x = 100; x > 0; x = x + x) {
sum = sum + x;
There are two versions: one where x is a float and one where it is an int. The question is are these infinite loops.
I am thinking that when x is an int, it will eventually overflow, making it less than zero and the loop will stop. When x is a float, x will reach infinity and the loop will be infinite.
Am I close?
The behavior when a signed integer is increased beyond its limit is undefined. So the loop may end or it may be infinite. Or it may crash (or the loop may never run at all). Or as some C gurus like to say, demons may fly out of your nose - though personally I doubt any compiler implementor would go through the trouble of implementing nasal demon functionality.
As far as floating point values are concerned, you are correct that it will be an infinite loop.
When signed integer overflows, the behavior is undefined. Expecting that x will become negative is naive at best.
Some compilers (like GCC) actually implement so called strict value semantics, which means that the compiler takes advantage of that undefined behavior for optimization purposes. In your specific example, the compiler might immediately generate a straightforward infinite loop, i.e. a loop that doesn't have any termination condition at all.
You are indeed correct, integers will overflow to negative values (as long as they're signed) so the loop will end, and floats will stick to "+infinity" which is always greater than any number except NaN.
Edit: I stand corrected, the int version does loop infinitely (on some compilers due to their assumptions): http://ideone.com/HZkht