3 ms·
>When you code C you code for the C virtual machine, not your CPU I code for my cpu, when I code C.
by gameswithgo 9y ago
>When you code C you code for the C virtual machine, not your CPU
I code for my cpu, when I code C.
- simias 9y agoYou might think you do but I can assure you that your C compiler is not aware of that. Here's a quick example to demonstrate why I mean, consider the following code that increments a variable and returns it. If the incrementation overflows it returns 0 instead: int increment_or_0(int a) { int res = a + 1; if (res < a) { /* Overflow */ return 0; } return res; } If you code "for your CPU" and your CPU is, say, x86-64 then you might think that this code ought to work. You add one to a and if the result is smaller than the original value of a then an overflow occurred. With 2's complement arithmetic that makes perfect sense. Yet built with gcc 7.3.0 using -O3 the compiler generates the following assembly: lea 0x1(%rdi),%eax retq In other words you have the incrementation but the overflow check is nowhere to be found. That's a perfectly valid optimization for a C compiler to make, because your code relies on an undefined behavior. In this case if you really want to write your test that way you can use the "-fwrapv" to tell GCC to assume fully defined integer overflow but then you're coding in a nonstandard dialect of C.
- icedchai 9y agoI believe K&R refers to it as an "abstract machine", not a "virtual machine." On (most) platforms, there's nothing virtual about it.
- simias 9y agoAh yeah, when I wrote it it felt wrong, although I think in context it's not ambiguous. I'm going to correct it, thanks.
- loeg 9y agoYou are correct about every published version of the C standard. C-next plans to standardized on 2's complement for signed integers, for what it's worth.[0] (For developers: additionally, as a non-standard feature, most popular open source compilers (i.e., gcc and clang) support an option called "-fwrapv", which does not treat 2's complement overflow as Undefined Behavior. This is useful for getting a large legacy codebase working on newer compilers, if it makes assumptions about 2's complement. Until the new C standard is published it's probably best to avoid relying on 2's complement overflow in new code.) [0]: https://twitter.com/jfbastien/status/989242576598327296 https://twitter.com/jfbastien/status/989242576598327296
- moefh 9y agoSigned overflow will still be undefined behavior even after the planned change (making signed integers 2's complement). This is explicitly mentioned in the page linked in that tweet: > Status-quo If a signed operation would naturally produce a value that is not within the range of the result type, the behavior is undefined. The author had hoped to make this well-defined as wrapping (the operations produce the same value bits as for the corresponding unsigned type), but WG21 had strong resistance against this.
- ksk 9y agoI think you're talking about code that doesn't work, while the person you replied to is taking about code that works. Yes, one should always strive to write conformant code, but in practice For e.g. no large x86 C project can 'just' be recompiled to PowerPC or ARM or X64.
- simias 9y agoMy point is that it's not possible to write code that works in C if you don't actually target the C abstract machine, unless you're using compiler extensions. It's not even about portability, as my example shows, it's just about basic correctness and having your code behave as expected. Knowing what kind of assembly to expect as the output of the compiler for a given C code is a useful skill for an advanced C programmer looking to write optimized programs but it's really an advanced topic. When I learned C in high school I only had a very fuzzy understanding of what a register was and how memory worked, it didn't stop me from writing useful C code. That's why I think it's a bad idea to give all these nitty-gritty details about CPU registers and the way the heap and stack are laid out in RAM because in practice C doesn't say anything about that (well, there's the register keyword I suppose). For a C tutorial it's more important to teach the C abstract machine and its rules than the way they map to a given piece of hardware. Take for instance this sentence from the article: >You can even tell the compiler to make sure it has an initial value. If you don't, its value may be random garbage that was there before in memory. I don't think that's a good thing to say. What you want to say is that the value is undefined and reading it is forbidden because that's what it really is. If you decide to use an undefined value somewhere in your code the compiler might swoop in and optimize it away, not use "random garbage that was there before in memory". Undefined is not random, undefined is not garbage, undefined is undefined. You might print it twice and get two different results. You might have a condition "if (uninitialized > 0)" and a condition "if (uninitialized <= 0)" and both may run, or maybe none will. Because there's no such thing as "random garbage in memory" in the C abstract machine, only defined and undefined values which are semantically different.