For someone who doesn't have the operator precedence rules memorized, it isn't clear whether the above code means this:
x = *stack;
stack--;
or this: stack--;
x = *stack;
Combining those two operations into one line is a trade-off I will never agree with. And I'm a fan of C myself: https://gist.github.com/cellularmitosis/3327379b151445c602ad... https://gist.github.com/cellularmitosis/d8d4034c82b0ef817913...The two-liner is actually the one which is simpler and more direct, as it requires less knowledge of operator precedence rules. The one-liner and two-liner compile to the same number of instructions, so I don't see how either "avoids inconsistent state".
Many expert-level C programmers tend towards one-liners. Here's an example from the original "Red book":
c = ((((i&0x8)==0)^((j&0x8))==))*255;
nooooo don't do it sadpanda.jpgIt's about performance, or thread safety, or anything like that; it's about having a coherent mental model of the code. A statement should, if possible, represent a single, complete operation. Invariants should not be violated by a statement, with respect to its environment. (This more true for 'push' than 'pop'.) One way of solving that is to bundle the 'push' and 'pop' operations up into functions; someone else in this thread did that. But why bother with the mental overhead of a function call when you could just represent the operation directly? To be sure, there are cases where the abstraction is warranted, but a two~three-line stack operation isn't abstraction, it's just indirection.
> For someone who doesn't have the operator precedence rules memorized, it isn't clear whether the above code means [snipped] or [snipped]
> The two-liner [...] requires less knowledge of operator precedence rules
It's not operator precedence—that's a separate issue; despite having implemented c operator precedence, I don't know all of them by heart—but simply behaviour of pre- and post-increment/decrement operations. It's even mnemonic—when the increment symbol goes before the thing being incremented, the increment happens first; else after—but even if not, it's a fairly basic language feature.
Even beyond that, though, it's an idiom. Code is not written in a vacuum. Patterns of pre- and post-increment fall into common use over time and become part of an established lexicon which is not specified anywhere. Natural language works the same way. Nothing wrong with that.
> It's even mnemonic—when the increment symbol goes before the thing being incremented, the increment happens first; else after—but even if not, it's a fairly basic language feature.
I think you missed the issue.
This is 100% about operator precedence, and has nothing to do with the decrement operator being in front of or behind the variable.
This expression:
*stack--
means either this: (*stack)--
or this: *(stack--)
depending on the operator precedence rules.If this is the layout of memory:
~~~~~~
stack-1: | 52 |
stack: | 23 |
stack+1: | 19 |
~~~~~~
(* stack)-- evaluates to 22, while *(stack--) evaluates to 52.Right, yes. I got confused by your example, because the example is definitely about pre- vs post-increment. My point about idioms still stands, though.
> (* stack)-- evaluates to 22, while * (stack--) evaluates to 52.
Actually, (* stack)-- evaluates to 23, but changes *stack to 22 :)
Thanks, I just realized I had that wrong :) https://pastebin.com/n7sHzW3p
int pop_int ()
{
int x = *stack;
--stack;
return x;
}
void push_int(int x)
{
++stack;
*stack = x;
}
Genunine questions:- Is this worse? - How does the state get inconsistent?
Relying on post-increment? Make sure it's a one line block that is totally unbraced with only single letter variable names if you do it because otherwise it's just faux-macho C and that's /weak/.
I think you're projecting. The point being made was that when you're writing a simple stack (as you often might do in C, since the standard library and the language itself conspire against providing you one) and you don't have the overhead to write multiple functions to wrap it up (vertical space is an issue when you make more than one of these–trust me, I used to write Java and every thing about it was just a papercut in verbosity), the post- and pre-increment versions are concise, idiomatic, and–to be honest–more clear simply because they use the operators in the way that they are meant to be used. I can glance at them and see, OK, this one gives me whatever the stack is pointing to and then makes it point to the next element; this one first moves the pointer to the next element (which is free) and sets it. All in one line. There's nothing to show off here, this is just how you write C; those operators exist for exactly this purpose (and IMO single letter variable names are generally only a good idea in the smallest of scopes, and I personally use braces even when optional).
int abc(int a, int b, int c)
{
}
I can do postincrement. I learned C the macho way. We all still have to read that crap. Now I know better when I'm writing it. I strongly disagree that a = *stack--;
*++stack = b
is better in any way beyond "I'm a macho C guy" than a = pop_int();
push_int(b);
https://en.wikipedia.org/wiki/Duff%27s_deviceIt's fun when you first see it. Sure.
I agree with saagarjha, there is nothing unclear or "crap" about using basic operators in an idiomatic way.
But this is as much beside the point under discussion as global pointers you raise.
Post-increment is an artefact from PDP-11 assembler and maps to a single instuction there. That's where it came from quite directly. It's completely unnecessary. Most modern languages find it useless enough they remove it. Python goes fine without it relying on +=, for example. (Although some do repeat C mistakes when basing their syntax on C, eg the unbraced, single line block that serves only to add non-zero probability of introducing a future bug but with the benefit of precisely nothing.. Hi Walter! Larry Wall cops flack for Perl syntax but he did not copy that.)
Post increment is hardly the end of the world it just isn't useful. It doesn't help readability. It can harm it. As a question of taste I find it lacking.
But hey, everyone else uses it, and duff's device is fun to read so go with them, knock yourself out.