33

Here is a simple piece of code where a division by zero occurs. I'm trying to catch it :

#include <iostream>

int main(int argc, char *argv[]) {
    int Dividend = 10;
    int Divisor = 0;

    try {
        std::cout << Dividend / Divisor;
    } catch(...) {
        std::cout << "Error.";
    }
    return 0;
}

But the application crashes anyway (even though I put the option -fexceptions of MinGW).

Is it possible to catch such an exception (which I understand is not a C++ exception, but a FPU exception) ?

I'm aware that I could check for the divisor before dividing, but I made the assumption that, because a division by zero is rare (at least in my app), it would be more efficient to try dividing (and catching the error if it occurs) than testing each time the divisor before dividing.

I'm doing these tests on a WindowsXP computer, but would like to make it cross platform.

Jérôme
  • 26,567
  • 29
  • 98
  • 120
  • `if (Divisor == 0) { std::cout << "Error."; exit; }`. You then eliminate every cause of this happening. Then you can remove the conditional and ship your product with no divide-by-zeroes. – Lightness Races in Orbit Jan 20 '11 at 14:01
  • (An `assert(Divisor != 0)` would be more canonical. Don't forget to develop by running through a debugger!) – Lightness Races in Orbit Jan 20 '11 at 14:04
  • 5
    This isn't even a FPU exception, but CPU exception. FPU handles floating-point numbers, but you'd get NaN or infinity with it, not a crash. – Sergei Tachenov Jan 20 '11 at 15:00
  • Rule of Thumb: ALWAYS (and in case you missed the emphasis: ALWAYS!) check your inputs before doing calculations and you avoid these types of issues. – Zac Howland Jan 20 '11 at 15:04
  • 2
    *"I made the assumption that, because a division by zero is rare (at least in my app), it would be more efficient"* - then don't make such assumptions before you run the profiler. Making assumptions out of the blue is one way to fail at optimizing. Trust your optimizer and your CPU's branch prediction. – Kos Jan 20 '11 at 15:56
  • Java does not have any problem: http://ideone.com/Ro5mw3. It probably tests every divisor before passing to the CPU. – Oliv Jul 17 '15 at 13:19

9 Answers9

36

It's not an exception. It's an error which is determined at hardware level and is returned back to the operating system, which then notifies your program in some OS-specific way about it (like, by killing the process).

I believe that in such case what happens is not an exception but a signal. If it's the case: The operating system interrupts your program's main control flow and calls a signal handler, which - in turn - terminates the operation of your program.

It's the same type of error which appears when you dereference a null pointer (then your program crashes by SIGSEGV signal, segmentation fault).

You could try to use the functions from <csignal> header to try to provide a custom handler for the SIGFPE signal (it's for floating point exceptions, but it might be the case that it's also raised for integer division by zero - I'm really unsure here). You should however note that the signal handling is OS-dependent and MinGW somehow "emulates" the POSIX signals under Windows environment.


Here's the test on MinGW 4.5, Windows 7:

#include <csignal>
#include <iostream>

using namespace std;

void handler(int a) {
    cout << "Signal " << a << " here!" << endl;
}

int main() {
    signal(SIGFPE, handler);
    int a = 1/0;
}

Output:

Signal 8 here!

And right after executing the signal handler, the system kills the process and displays an error message.

Using this, you can close any resources or log an error after a division by zero or a null pointer dereference... but unlike exceptions that's NOT a way to control your program's flow even in exceptional cases. A valid program shouldn't do that. Catching those signals is only useful for debugging/diagnosing purposes.

(There are some useful signals which are very useful in general in low-level programming and don't cause your program to be killed right after the handler, but that's a deep topic).

Kos
  • 70,399
  • 25
  • 169
  • 233
  • 3
    Windows has a nice frame-based exception handling facility (and probably the C++ exception framework is built on the Windows facility). It is possible via a compiler switch to turn hardware exceptions into C++ exceptions, though you need to take care - over-zealous fault handling can get you into undefined states. (Note, by the way, I persist in calling divide-by-zero an exception: the OS and hardware will confirm it's an exception, it's just not a C++ exception). EDITED: oops, overlooked the MinGW part of the question. That likely changes a lot. I'll leave my waffling here anyway. – dave May 05 '12 at 14:29
  • Can you please add some good reference for signals (especially those not killing processes)? – Paweł Szczur Oct 26 '12 at 07:46
  • 2
    It's OS-specific. POSIX defines these; Windows isn't POSIX-compilant but MinGW does its best to bridge the gap a bit. For Linux you have [this man page](http://unixhelp.ed.ac.uk/CGI/man-cgi?signal+7), common examples of "non-lethal" singals are SIGSTOP, SIGTSTP (temporary stop) and SIGCONT (continue). – Kos Oct 26 '12 at 16:43
  • Same people are not restricted by POSIX and thus are able to catch such exceptions using a catch block. Let's see how many years it still will take, until the functionality makes it into LINUX. The matching option (-fnon-call-exceptions) is already available but intended for apples OS. –  Feb 24 '14 at 21:00
13

Dividing by zero is a logical error, a bug by the programmer. You shouldn't try to cope with it, you should debug and eliminate it. In addition, catching exceptions is extremely expensive- way more than divisor checking will be.

You can use Structured Exception Handling to catch the divide by zero error. How that's achieved depends on your compiler. MSVC offers a function to catch Structured Exceptions as catch(...) and also provides a function to translate Structured Exceptions into regular exceptions, as well as offering __try/__except/__finally. However I'm not familiar enough with MinGW to tell you how to do it in that compiler.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 4
    +1 for the advice to fix the hole in the wall rather than trying to hang a picture over it. – John Dibling Jan 20 '11 at 14:00
  • 2
    +1 for saying that checking a condition is cheaper than catching an exception. – Paweł Szczur Oct 26 '12 at 07:49
  • checking is only cheaper than an exception for very trivial code –  Feb 24 '14 at 20:55
  • Not always true - consider scientific computing, where 0.0 in general has some finite but small probability of occurring. – FreelanceConsultant Feb 26 '15 at 13:53
  • @user3728501: float a=1, b=0, c; c=a/b; is a valid #inf and float a=0, b=0, c; c=a/b; is a valid #nan which can be tested. Also its possible to check if(b==0) bailout(); – Cem Kalyoncu May 07 '15 at 20:22
  • 3
    I don't agree that "division by zero==programmer bug". Imaging you run a complex algorithm on a bunch of unpredictable input data(data from external source, disk file, network etc) which could possibly cause division by zero, then you realize checking zero before each use of `/` operator is very cumbersome. Then, something like Windows SEH is such a good rescue. – Jimm Chen Dec 23 '15 at 14:44
8
  1. There's isn't a language-standard way of catching the divide-by-zero from the CPU.

  2. Don't prematurely "optimize" away a branch. Is your application really CPU-bound in this context? I doubt it, and it isn't really an optimization if you break your code. Otherwise, I could make your code even faster:

    int main(int argc, char *argv[]) { /* Fastest program ever! */ }
    
Greg D
  • 43,259
  • 14
  • 84
  • 117
6

Divide by zero is not an exception in C++, see https://web.archive.org/web/20121227152410/http://www.jdl.co.uk/briefings/divByZeroInCpp.html

Sven van den Boogaart
  • 11,833
  • 21
  • 86
  • 169
ismail
  • 46,010
  • 9
  • 86
  • 95
3

Somehow the real explanation is still missing.

Is it possible to catch such an exception (which I understand is not a C++ exception, but a FPU exception) ?

Yes, your catch block should work on some compilers. But the problem is that your exception is not an FPU exception. You are doing integer division. I don’t know whether that’s also a catchable error but it’s not an FPU exception, which uses a feature of the IEEE representation of floating point numbers.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • FPU exceptions are not caught by `catch(...)` in standard C++. But at least one compiler has supported it, long ago. Namely, Visual C++ once had that as a language extension. I believe, seem to recall, that extension was present in version 6.0, which was pre-standard, and was dropped in version 7.0, the first Visual Studio.NET version and post C++98. – Cheers and hth. - Alf Apr 04 '16 at 11:35
1

On Windows (with Visual C++), try this:

BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
    __try 
    { 
        *pResult = dividend / divisor; 
    } 
    __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? 
             EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    { 
        return FALSE;
    }
    return TRUE;
}

MSDN: http://msdn.microsoft.com/en-us/library/ms681409(v=vs.85).aspx

Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114
jalal sadeghi
  • 362
  • 4
  • 19
  • no need to use this ancient try-catch but the normal C++ try-catch with (...) is also doing it -- assuming that compiler option /EHa is used. –  Apr 24 '16 at 20:00
0

To avoid infinite "Signal 8 here!" messages, just add 'exit' to Kos nice code:

#include <csignal>
#include <iostream>
#include <cstdlib> // exit

using namespace std;

void handler(int a) {
    cout << "Signal " << a << " here!" << endl;
    exit(1);
}

int main() {
    signal(SIGFPE, handler);
    int a = 1/0;
}
nibrot
  • 11
  • 1
  • 2
0

Well, if there was an exception handling about this, some component actually needed to do the check. Therefore you don't lose anything if you check it yourself. And there's not much that's faster than a simple comparison statement (one single CPU instruction "jump if equal zero" or something like that, don't remember the name)

Atmocreations
  • 9,923
  • 15
  • 67
  • 102
-1

As others said, it's not an exception, it just generates a NaN or Inf.

Zero-divide is only one way to do that. If you do much math, there are lots of ways, like
log(not_positive_number), exp(big_number), etc.

If you can check for valid arguments before doing the calculation, then do so, but sometimes that's hard to do, so you may need to generate and handle an exception.

In MSVC there is a header file #include <float.h> containing a function _finite(x) that tells if a number is finite. I'm pretty sure MinGW has something similar. You can test that after a calculation and throw/catch your own exception or whatever.

Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
  • 2
    This would be true for floats, but this example is with integers, therefore no NaN and no inf, CPU generates a signal/structured exception/whatever you want to call it instead. – Suma Jan 25 '11 at 15:30
  • 1
    @Suma: Touche'. BTW, haven't argued with you for a while. Hope things are well. – Mike Dunlavey Jan 25 '11 at 18:30