Hacker News new | ask | show | jobs
by pascal_cuoq 4892 days ago
I agree with all your arguments. The function pointer <-> void pointer conversion in particular is an excellent example. But the very last example, unsigned -> signed conversion, is not a good illustration of the point you are making then.

unsigned -> signed conversion is already “implementation-defined behavior” (as opposed to “undefined behavior”). The standard does not guarantee how it behaves but forces compilers to make a choice and to stick to it.

A different example, of a behavior that is really undefined, would be signed arithmetic overflow:

int detect_max(int x) { return x+1 < x; }

The function above branchlessly detects that its argument is INT_MAX, and returns 1 in this case thanks to 2's complement representation.

Except that it doesn't. The command “gcc -O2” compiles it into “return 0;”. GCC can do this, because signed arithmetic overflow is undefined behavior. The compiler is only taking advantage of undefined behavior in a way locally convenient.

Now that two's complement is (almost) everywhere, making it the standard for signed arithmetic overflows is the sort of bold choice I would like to see, but it won't happen (it would break GCC's existing optimization).

1 comments

Good point about undefined vs. implementation-defined, though even implementation-defined behavior could break programs that switch to a different implementation that makes a different choice.