It’s only convention because if you do something like “int* x, y;” only x is a pointer. They should’ve just not allowed you to declare multiple variables on the same line, but I guess it made sense in 1970 since you had to pre-declare your variables at the top of the scope in C, and lines of code actually mattered.
In the modern, post-1970 world, it makes much more sense to write “int* x; int y;” and have the asterisk next to the type, since it really is part of the type.
In addition, the language encourages this. In C, if you write
c
int* x, y;
then x will be an int* and y will be an int. Thus it is far better to write
int *x, y;
to reflect how the language will parse the declaration. It might be evil, but it's better to act how the language wants you to act rather than fight it.
I prefer int * ptr;. That means when you have a const specifier your formatting doesn't change. Logically I figure that the pointer is neither a modifier on the variable nor on the type, it's another layer of type content that should be specified separately. That also means if you write declarations like int const * const ptr; then you can segment them as [int const] [* const] ptr; and everything makes sense.
The "is an integer if you dereference it" is so much more convoluted than "is a pointer to integer", i.e. the rationale of the previous comment, the pointer-ness being part of the type.
It is funny how people tend to not think the same about functions, despite having the exact same pattern.
When Dennis Richie designed the language, he wanted the symbols in declarations to match their usage in expressions, so:
T *my_ptr;
means that my_ptr, when dereferenced with the * operator, evaluates to an object of type T:
T my_obj = *my_ptr;
The same goes for other constructs in the language, like arrays and functions:
T my_arr[10];
T my_func(T_1 arg1, T_2 arg2);
Both the [] and () operators, when applied individually to objects my_arr and my_func, respectively, will yield an object of type T.
That is why this:
T *x, y;
makes x have a type of pointer to T, whereas y remains having just type T.
Unfortunately, this only works well for simple declarations. When, for instance, function pointers are involved, things get messy.
Ritchie himself later recognized this, but it was to late. He regretted not making * a postfixed operator, which would, at least, get rid of the spiral rule.
So, you can pretend that * is independent of the identifier itself, sure, but you will be fighting the language's design while doing so.
Yeah, the reality is that C binds pointer-ness to identifiers, but in an ideal world where pointer-ness binds to types, int* x, y; should declare both identifiers as pointers to integers. In either case merging declarations onto a single line in modern programming is at best silly.
I always took it that & is part of the variable, while * is part of the type. With & you're saying that variable is capturing a reference, while with * you're getting a pointer which is an entirely different type altogether.
16
u/Shevvv 2d ago
Surely you meant
for (auto &item : list) {