Is there a convention for pointer declarations in

2020-05-23 01:03发布

问题:

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 8 years ago.

When declaring pointers in C, there are 3 variants:

Variant A:

int* ptr;

Variant B:

int *ptr;

Variant C:

int * ptr;
  • In A, the indirection operator has been appended to the type.
  • In B, the indirection operator has been prepended to the variable.
  • In C, the indirection operator stands freely in between type and variable.

The way a pointer is declared differs depending on the type of documentation I read. Some authors seem to have a preference for certain variants, others use several.

  • Am I correct to assume that there is no difference in functionality between the different variants?
  • If yes, is there a convention for which variant one should be using in C?

回答1:

There is absolutely no difference in functionality between

int* ptr;

and

int *ptr;

Which you use is up to you, there are multiple conflicting coding styles to choose from.



回答2:

Something nobody else has mentioned is that

int *ptr;

corresponds more closely to the language grammar.

  • int *ptr; is a declaration, which consists of:
    • a declaration-specifier int, followed by
    • a declarator, *ptr.

(That actually skips a number of steps, but it gets the basic idea across.)

Since declaration follows use, what this means is that *ptr is of type int. It follows from this that ptr is of type int*.

One could argue that this makes it better than

int* ptr;

for the same reason that

x = y+z;

is better than

x=y + z;

Of course you can write

int* ptr;

and read it as "ptr is of type int*". And plenty of programmers do exactly that, and get along just fine (it tends to be the preferred style in C++). The compiler doesn't care which way you do it, and anyone reading your code shouldn't have trouble understanding it either way.

But whichever spacing you choose, you need to understand what int *ptr; really means, so that when you see

int *ptr, i;

in someone else's code (as you inevitably will), you'll immediately understand that ptr is a pointer and i is an int.

And if you're working with other programmers on a project, you should follow whatever existing convention is in the coding standards, or if there isn't one, the way the code is already written. I personally prefer int *ptr; to int* ptr;, but using a mixture of both styles is far worse than using either one consistently.



回答3:

It matters only when you plan to declare multiple variables of the same type on the same line. For example, if you want multiple int pointers, you need to do this:

int *a, *b, *c;

Stylistically though, this is confusing when you're only declaring a single variable. Many people like to see the type followed by the variable name, and the type is supposed to be pointer to int, not int, so they prefer:

int* a;
int* b;
int* c;

It's ultimately up to you whether you prefer one form over the other. In 20 years of programming C professionally, I've seen about 50% of people choose one over the other.



回答4:

T *a;

is the preferred C style for declaring a pointer to T as used in Kernighan & Ritchie's book about C, as well as in ISO/IEC 9899:2018.

T* a;

is the preferred C++ style way to a declare pointer to T as used in Stroustrup's book about C++.

Both notations are equivalent.



回答5:

They both mean the same as others have said. There is a trap waiting for you though. Consider this code:

int* a, b;

You might think that this declared to pointers to int. No so but otherwise. In fact a is int* but b is int. This is one of the reasons for many C programmers preferring to put the * next to the variable rather than the type. When written like this:

int *a, b;

you are less likely to be misled as to what a and b are.

Having said all that, many coding standards insist that you declare no more than one variable per line, i,e.

int* a;
int b;

If you follow the one variable per line rule then there is definitely no scope for confusion.



回答6:

C declarations are based around the types of expressions, not objects.

If you have a pointer to an int named pi, and you want to access the integer value that it points to, you have to dereference the pointer, as in:

x = *pi;
printf("%d", *pi);
*pi = 1 + 2;

etc. The type of the expression *pi is int: therefore, the declaration should read as

int *pi;

Now let's suppose you had an array of pointers to char; to get to any character, you need to first subscript into the array, then dereference the result:

c = *pc[i];
if (*pc[j] == 'a') {...}

etc. Again, the type of the expression *pc[i] is char, so the declaration reads as

char *pc[N];

Both *pi and *pc[N] are known as declarators, and specify additional type information not given by the type specifier. IOW, the array-ness and pointer-ness of pc are specified as part of the declarator, while the char-ness is given by the type specifier.

As to the question of which is style is proper...

Neither one is "right", but I (and many other C programmers) prefer to write T *p as opposed to T* p, since it more closely reflects the language grammar (the * is part of the declarator) and it helps avoid confusion when declaring multiple items. I've seen far too many examples of people writing T* a, b; and expecting b to be a pointer.

The usual response to that criticism is "don't declare more than one item per line." My response to that response is "write your declarators correctly and you won't have any problems".

There's a different school of thought among many C++ programmers, who prefer the T* p style, and I have to say there are a few cases (limited to C++) where it can make the code more readable.

However, that only works for simple pointers to T: the paradigm rapidly breaks down when you start dealing with arrays of pointers, or pointers to arrays, or pointers to functions, or pointers to arrays of pointers to functions, etc. I mean, writing something like

T* (*(*p)[N])(); // p is a pointer to an array of pointers to functions
                 // returning pointers to T.

just indicates confused thinking. Although, if you really really really feel that you must follow the T* p paradigm, you could always create a series of typedefs:

EDIT

Let's try that again:

typedef T* TPtr;                           // pointer to T
typedef TPtr TPtrFunc();                   // function returning pointer to T
typedef TPtrFunc* TPtrFuncPtr;             // pointer to function returning
                                           // pointer to T
typedef TPtrFuncPtr TPtrFuncPtrArray[N];   // N-element array of pointer to function
                                           // returning pointer to T

TPtrFuncPtrArray* p;

For the love of God, don't do that.



回答7:

In C, whitespace does not matter except where it is needed to separate tokens. Both your variants are syntactically correct.

Variant 1 associates the pointer operator with the type, which is logical enough. For me, that would be enough if there wasn't for the reason why Variant 2 makes sense.

Variant 2 is consistent with the way C declarations are structured. In the C grammar, the pointer operator belongs in the declarator (that is, with the name), not the type. This matters when declaring multiple variables in the same declaration. There are also a number of more esoteric cases where it matters.

Thus, for me, Variant 2 is more consistent with C. But either variant is defensible, and both variants are conventional.



回答8:

You are correct, both mean exactly the same thing to the compiler. Both statements will produce a variable of type (int *).

As for which is correct: Can of worms! That is a debate topic usually. If you work for a company or on OSS, it's probably best to defer to a defined coding style. If there isn't one I usually go the the LNT (leave no trace) style of matching whatever style has evidentially been used in this part of the code base.

It can be argued that to the reader one is easier to understand. For example int* ptr; puts the * closer to the int which more clearly communicates the we are talking about an (int *) type...