5 ms·
The real issue isn't that C doesn't have a standard int overflow, but that it's undefined. What they could have done is made it implementation defined, like si
by greenhouse_gas 8y ago
The real issue isn't that C doesn't have a standard int overflow, but that it's undefined.
What they could have done is made it implementation defined, like sizeof(int), which depends on the implementation (hardware) but on the other hand isn't undefined behavior (so on x86/amd4 sizeof(int) will always be equal to 4).
- paulddraper 8y ago> on x86/amd4 sizeof(int) will always be equal to 4 Nothing is stopping your C compiler from making the guarantee sizeof(int)=4 on x86/amd64.
- wyldfire 8y agoI think you are in agreement with the comment you are replying to.
- paulddraper 8y agoThe comment suggested the standard make it implementation defined rather than undefined. There's not a meaningful difference here. Even today, an implementation may define unsigned overflow.
- wyldfire 8y agoOh, I see, I wonder if greenhouse_gas is suggesting a feature similar to sizeof() that can be used to portably adapt your program's design to the target's overflow capability.
- unwind 8y agoC language lawyer in training: sizeof is not a function. The parentheses are part of the operand and only needed for type names, to make them into cast expressions.
- Someone 8y agoYes, there is. Implementation defined means that a conforming implementation _must_ document its behavior. That means that programmers don’t have to use trial and error to figure out how the compiler behaves and don’t have to _hope_ they found all the corner cases.
- berti 8y agoAnd that is how we get #if defined(_THIS_THING_SOME_COMPILER_DEFINES) && !defined(__BUT_NOT_THIS_ONE_THAT_COMPILER_X_DEFINES) soup ;)
- greenhouse_gas 8y agoBetter than than silently ignoring an if guard preventing an overflow, and then overflowing anyways on addition.
- cjensen 8y agoIt's undefined for a reason. size_t size = unreasonable large number; char buf = malloc (size); char *mid = buf + size / 2; int index = 0; for (size_t x = 0; x < big number; x++) mid[index++] = x; A common optimization by a compiler is to introduce a temporary char *temp = mid + index; prior to the loop and then replace the body of the loop with *(temp++) = x; If the compiler has to worry about integer overflow, this optimization is not valid. (I'm not a compiler engineer. Losing the optimization may be worth-while. Or maybe compilers have better ways of handling this nowadays. I'm just chiming in on why int overflow is intentionally undefined in the Fine Standard)
- rom1v 8y agosize_t is unsigned, overflow is defined.
- JdeBP 8y agoThe type of index is, however, signed int.
- rom1v 8y agoYou're right, I read diagonally :) However, the optimization argument for signed overflow seems weird to me, because I can't see any reason why this argument would not apply to unsigned overflow as well. If we keep undefined behavior to optimize things like "if (n < n + 1)" when n is signed, why not do the same when n is unsigned? Conversely, if there is a good reason not to, then why would it not apply to signed overflow as well?
- unwind 8y agoYou meant char * buf = malloc(size); You dropped an asterisk. Since changing pointers returned by malloc() is a bad idea, I'd make it: char * const buf = malloc(size);
- kazinator 8y agoThis is only useful if buf is involved in some preprocessor macrology which perpetrates a hidden mutation of buf. BIG_MACRO(x, y, z, buf); // error! the programmer is informed that, to his or her surprise, BIG_MACRO mutates buf and can take appropriate corrective action. It's also useful in C++, since innocent-looking function calls can steal mutable references: cplusplusfun(x, y, z, buf); // error: arg 4 is non-const ref No such thing in C, though; function calls are pure pass-by-value. Changing pointers returned by malloc is sometimes done: if ((newptr = realloc(buf, newsize)) != 0) buf = newptr; else ... In my experience, C code doesn't use const for anywhere near all of the local variables which could be so qualified. If you enact a coding convention that all unchanged variables must be const, the programmers will just get used to a habit of removing the const whenever they find it convenient to introduce a mutation to a variable. "Oh, crap, error: x wasn't assigned anywhere before so it was const according to our coding convention. Must remove const, recompile; there we go!" If you want to actually enforce such a convention of adding const, you need help from the compiler: a diagnostic like "foo.c: 123: variable x not mutated; suggest const qualifier". I've never seen such a diagnostic; do you know of any compiler which has this? I think that the average C module would spew reams of these diagnostics.
- ridiculous_fish 8y agoThe modern case for keeping signed overflow as UB is that it unlocks compiler optimizations. For example, it allows compilers to assume that `x+1>x`. If implementations are forced to define signed overflow, then these optimizations are necessarily lost. So implementation-defined is effectively the same as fully-defined.
- Sean1708 8y agoI suppose the question is, which of these optimisations are actually useful for the compiler to do automatically? Yours is the example that's always thrown about, but it always seems like the kind of optimisation that the programmer should be responsible for.
- int0x80 8y agoJust a nitpick. Implementation is about the particular compiler and runtime (stdlib) implementation, not the hardware. Hardware is the platform hosting the implementation (this are ISO C-standard defined terms). A compiler targeting x86 platform can implement sizeof int == 8, or whatever it pleases, as far as C std is concerned. In practice compilers dont get creative about this. But there are real world cases where stuff is different, for example: http://www.unix.org/version2/whatsnew/lp64_wp.html http://www.unix.org/version2/whatsnew/lp64_wp.html