Yes you're right; in retrospect I should have used quotes around the phrase "type-operator" or something, this is entirely my wording. And also I'm using 'operator' here loosely, to mean an operation conducted via a symbol and some 'operands', which are not necessarily expressions, or expected to return another expression. (casting works a similar way, for instance, in that it is typically talked of as an operator, but one of the operands is a type rather than an expression, and it's debatable whether the operation actually 'returns' something or simply causes a particular type-interpretation as a side-effect).

So effectively I like to think of all symbols in a declaration statement as "operators" in some broader sense. As you say, you could think of this as "returning a type", semantically speaking, though I think more usefully I would talk about the operator as having the particular operational side-effect of allocating the correct kind of memory for that object, as per the declared type. Of course I realise that the language doesn't formally define these symbols as 'operators acting in a declaration context' as such in the standard; but, equally, the actual wording doesn't prevent you from viewing these symbols in such an operational manner either. And I find thinking of them as operators in this manner to be more informative and predictive than the super-reductive "it's just what the syntax is", which could be applied to any part of the language, reducing all discussion about semantics to nothing.

And "comma type-operator" because, well, inevitably if I just call it "comma operator", even if I'm explicitly pointing out the fact that I'm talking about the declaration rather than the expression context, someone will miss the point anyway and fixate on the fact that "this is not the comma operator" (which would be technically correct but totally not the point); therefore I take some creative liberties and refer to it as a "type-operator", in that it only carries these semantics in a declaration context :)

Regarding the granny knot analogy, I agree, but at the same time you could argue that complexity is a matter of perspective, and therefore one could argue similarly that you might as well disambiguate int * a by treating it as an operator (semantically speaking) and thus spacing it properly, and putting each declaration on a single line, as opposed to oversimplifying syntax by relying on arbitrary proximity conventions, in order to combining a bunch of declarations together; which would be like saying I'm hoping this knot is too simple to be a reef knot, I'm hoping nobody will think it's a reef knot, so no need for a double knot here. :p

In any case, I don't necessarily disagree with placing the asterisk close to the variable, but I consider this mostly a stylistic issue, and stylistically I prefer spacing the two. What I do object to is that this is the one correct way; I think it's prone to interpretation problems as much as the others (the specific issue you pointed out notwithstanding), and one should prefer proper grouping for disambiguation, rather than relying on proximity conventions. So to the extent that spacing things encourages one to provide clearer groupings and keep things in separate lines, leading to more robust code, I would prefer spacing for that reason alone.

(unless my team's style guide forced me to, of course. I'm not going on a holy war over this, it's just my preferred style/philosophy :D )

(sorry for the long reply, I'm bored in a cafe and procrastinating from actual work. thanks for the discussion and food for thought!)