Is dividing by zero accompanied with a runtime error ever useful in C++?

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-13 04:26:10

问题


According to C++ Standard (5/5) dividing by zero is undefined behavior. Now consider this code (lots of useless statements are there to prevent the compiler from optimizing code out):

int main()
{
    char buffer[1] = {};
    int len = strlen( buffer );
    if( len / 0 ) {
        rand();
    }
}

Visual C++ compiles the if-statement like this:

sub         eax,edx 
cdq 
xor         ecx,ecx 
idiv        eax,ecx 
test        eax,eax 
je          wmain+2Ah (40102Ah) 
call        rand

Clearly the compiler sees that the code is to divide by zero - it uses xor x,x pattern to zero out ecx which then serves the second operand in integer division. This code will definitely trigger an "integer division by zero" error at runtime.

IMO such cases (when the compiler knows that the code will divide by zero at all times) are worth a compile-time error - the Standard doesn't prohibit that. That would help diagnose such cases at compile time instead of at runtime.

However I talked to several other developers and they seem to disagree - their objection is "what if the author wanted to divide by zero to... emm... test error handling?"

Intentionally dividing by zero without compiler awareness is not that hard - using __declspec(noinline) Visual C++ specific function decorator:

__declspec(noinline)
void divide( int what, int byWhat )
{
    if( what/byWhat ) {
       rand();
    }
}

void divideByZero()
{
    divide( 0, 0 );
}

which is much more readable and maintainable. One can use that function when he "needs to test error handling" and have a nice compile-time error in all other cases.

Am I missing something? Is it necessary to allow emission of code that the compiler knows divides by zero?


回答1:


There is probably code out there which has accidental division by zero in functions which are never called (e.g. because of some platform-specific macro expansion), and these would no longer compile with your compiler, making your compiler less useful.

Also, most division by zero errors that I've seen in real code are input-dependent, or at least are not really amenable to static analysis. Maybe it's not worth the effort of performing the check.




回答2:


Dividing by 0 is undefined behavior because it might trigger, on certain platforms, a hardware exception. We could all wish for a better behaved hardware, but since nobody ever saw fit to have integers with -INF/+INF and NaN values, it's quite pointeless.

Now, because it's undefined behavior, interesting things may happen. I encourage you to read Chris Lattner's articles on undefined behavior and optimizations, I'll just give a quick example here:

int foo(char* buf, int i) {
  if (5 / i == 3) {
    return 1;
  }

  if (buf != buf + i) {
    return 2;
  }

  return 0;
}

Because i is used as a divisor, then it is not 0. Therefore, the second if is trivially true and can be optimized away.

In the face of such transformations, anyone hoping for a sane behavior of a division by 0... will be harshly disappointed.




回答3:


If the compiler detects a division-by-0, there is absolutely nothing wrong with a compiler error. The developers you talked to are wrong - you could apply that logic to every single compile error. There is no point in ever dividing by 0.




回答4:


In the case of integral types (int, short, long, etc.) I can't think of any uses for intentional divide by zero offhand.

However, for floating point types on IEEE-compliant hardware, explicit divide by zero is tremendously useful. You can use it to produce positive & negative infinity (+/- 1/0), and not a number (NaN, 0/0) values, which can be quite helpful.

In the case of sorting algorithms, you can use the infinities as initial values representing greater or less than all possible values.

For data analysis purposes, you can use NaNs to indicate missing or invalid data, which can then be handled gracefully. Matlab, for example, uses explicit NaN values to suppress missing data in plots, etc.

Although you can access these values through macros and std::numeric_limits (in C++), it is useful to be able to create them on your own (and allows you to avoid lots of "special case" code). It also allows implementors of the standard library to avoid resorting to hackery (such as manual assembly of the correct FP bit sequence) to provide these values.




回答5:


Detecting divisions by zero at compile-time is the sort of thing that you'd want to have be a compiler warning. That's definitely a nice idea.

I don't keep no company with Microsoft Visual C++, but G++ 4.2.1 does do such checking. Try compiling:

#include <iostream>

int main() {
    int x = 1;
    int y = x / 0;
    std::cout << y;
    return 0;
}

And it will tell you:

test.cpp: In function ‘int main()’:
test.cpp:5: warning: division by zero in ‘x / 0’

But considering it an error is a slippery slope that the savvy know not to spend too much of their spare time climbing. Consider why G++ doesn't have anything to say when I write:

int main() {
    while (true) {
    }
    return 0;
}

Do you think it should compile that, or give an error? Should it always give a warning? If you think it must intervene on all such cases, I eagerly await your copy of the compiler you've written that only compiles programs that guarantee successful termination! :-)



来源:https://stackoverflow.com/questions/7790272/is-dividing-by-zero-accompanied-with-a-runtime-error-ever-useful-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!