6 ms·
The way I learned that in C a long time ago was "post increment" was "post statement increment".
by micro-ram 13y ago
The way I learned that in C a long time ago was "post increment" was "post statement increment".
- dnautics 13y agoexactly. This is precisely to spec; and I got the answer of 60 immediately on looking at the code.
- haberman 13y agoThis is incorrect; it is undefined behavior according to the spec: http://www.reddit.com/r/programming/comments/1rrefp/a_glimpse_of_undefined_behavior_in_c/cdq54q4 http://www.reddit.com/r/programming/comments/1rrefp/a_glimps...
- micro-ram 13y agoOk, so do any other compilers handle it differently?
- randyrand 13y agoExactly. De facto defined is usually just as important to consider as de jure.
- tedunangst 13y agoPractically every new version of gcc adds a new optimization that recognizes some new form of undefined behavior and then rewrites your function to do whatever it wants. Classic example: signed integer overflow. It worked for decades. Then one day it didn't. If you want to know about this particular example: https://news.ycombinator.com/item?id=6824514 https://news.ycombinator.com/item?id=6824514 (not personally confirmed)
- army 13y agoThat isn't really an accurate description of the issues: it's not the case that it was "working" and then "broken" by GCC maintainers. It's always been unsupported and not worked in specific situations, but for 99% of code it appeared to GCC users that it was supported. The signed integer overflow behaviour was never guaranteed by old versions of GCC, and code exploiting it would not always be compiled with the "expected" behaviour. It's just as the GCC optimizer has improved there are more circumstances when it does optimisations that hinge on the assumption. Compiler users generally want something that "just works" and doesn't do anything unexpected, but in the case of a low-level language like C, doing away with undefined behavior essentially would mean pessimistically avoiding many optimisations on the 99%+ of straightforward, reasonable code out there in favor of not doing anything surprising on the remaining fraction of dubious code that depends on certain things happening in scenarios where behavior is undefined according to the C standard. There are languages that make that choice, but C isn't one of them.
- tedunangst 13y agoThat is my point. De facto working code is not working code. I have fixed feelings about the integer overflow issue because it's so easy to trigger, unlike triple post increment fake examples. And it usually results in a security problem. For very little benefit, IMO.
- quesera 13y agoYep. Clang says: zsh% clang -o sequencepoints sequencepoints.c sequencepoints.c:7:18: warning: multiple unsequenced modifications to 'i' [-Wunsequenced] int r = 1 * a[i++] + 2 * a[i++] + 3 * a[i++]; ^ ~~ 1 warning generated. And prints: zsh% ./sequencepoints 140
- dnautics 13y agoah, sorry, I'm stuck in C[whatever it was I learned in high school]
- jfoutz 13y agoit's a little weirder though. int main(int argc, char argv) { int a = 0; printf("%i %i %i\n", a, a++, a++); } will give "0 0 1" (gcc 4.2.1), the increment "shouldn't" happen until after the ; if you're going with post statement. I think your rule would expect "0 0 0" with a being 2 after the printf. BUT! you get a warning, so that's nice.
- jacquesgt 13y agoThe issue here is that the order of function argument evaluation is undefined. If the commas weren't inside of a function call, they would result in sequence points. So, this would be well defined: int a = 0, b, c; b = a++, c = a++; But, there is no defined order in which to evaluate function arguments.
- NAFV_P 13y agoThe example given in the article shows all the code, but your example involves a function so the code in question is hidden. The behaviour partially depends on how the function is written. "0 0 1" is what I would expect from your code, and identifier a should end up as 2.
- agumonkey 13y agoI can't help but to put this in the same bag as javascript lack of block scope, exemplified in the famous for loops counter undesired effects.
- ballard 13y agoThere was a popular myth way back in the 90's that preincrement was always faster than postincrement because the former could generate a temporary. As if this were the case: /* x++ */ inline int postincrement(int *x) { int temp = *x; *x = *x + 1; return temp; } /* ++x */ inline int preincrement(int *x) { *x = *x + 1; return *x; } But in typical usage, where the expression value is not used, it doesn't make any difference: for (int i = 0; i < 10; ++i) { If one looks at the assembly, it's clearly equivalent to: for (int i = 0; i < 10; i++) { Incidently, the latter seems more readable.
- ezy 13y agoI always thought this "myth" was confined to C++ code (iterators) where there may in fact be code that does something analogous to what your "postincrement()" does. Compilers are sometimes smart enough to remove the unnecessary operation in C++ (e.g. switch to ++x themselves), but I always use ++i for the same reason people simplify their usage of C in between sequence points --- it's an easy transformation, and why tempt fate?
- nly 13y agoThe compiler can't necessarily optimise i++ away in C++, because the ++operator or the destructor of the temporary iterator object returned may have side effects. It's still not quite equivalent to ballards postincrement() though, because the C++ standard allows for that temporary copy operation to be optimised away
- bookface 13y agoI was actually asked in an interview at Google in 2011 whether pre- or postincrement was faster in a snippet of code where the expression's value wasn't used. When I said that I was pretty confident that the compiler would produce the same assembly in both cases, the interviewer insisted that pre- was faster based on the same logic you mentioned. To her credit, she didn't penalize me for disagreeing with her and I still got the offer.
- nilkn 13y ago