標籤:

C/C++ 里指針聲明為什麼通常不寫成 int* ptr 而通常寫成 int *ptr ?

int* ptr = a;

明顯要比

int *ptr = a;

更符合語意吧。前者把 int* 當成一個運算元作用在 ptr 上,聲明 ptr 是一個指針變數,儲存了變數 a 的地址。而後一種語意明顯不一致,*ptr 本來就表示 a 的值,而聲明的時候好像是把變數 a 的地址賦給指針指向的變數。此外 ptr 本來就等於 a ,所以我想按前一種的寫法不是更符合語意的一致性嗎?

-------------------------------------------

補充一點,我知道在

int* var0, var1;

這種聲明下 var0 是 int 型指針,var1 是 int 類型。但是這種破壞一致性的語意難到不反人類嗎?

-------------------------------------------

再補充一點,其實寫成 int *ptr 也可已理解,就像 @馮東 和@顧笑群 回答里的解釋。但是在用數組給指針初始化的時候又可以寫成 int* ptr = ary, 既然 ary 能表示 ary[0] 的地址,那為什麼不能在用原始類型給指針初始化的時候寫成 int* ptr = a ? 這樣也更符合上面兩個答案里的意思。


希望大家不要繼 tab vs space、{ 是否換行之後,再搞多兩個派別。

如果要搞,可以再加多兩種:

int *p; // 1. 很多書都這樣寫吧
int* p; // 2. 我好像近十年習慣這麼寫
int * p; // 3. 一人讓一步吧
int*p; // 4. 異類!拖出去!

.


C++ Style and Technique FAQ

C++之父的解釋

他的個人主頁寫的東西很值得一讀。

Is ``int* p;"" right or is ``int *p;"" right?

Both are "right" in the sense that both are valid C and C++ and both have exactly the same meaning. As far as the language definitions and the compilers are concerned we could just as well say ``int*p;"" or ``int * p;""

The choice between ``int* p;"" and ``int *p;"" is not about right and wrong, but about style and emphasis. C emphasized expressions; declarations were often considered little more than a necessary evil. C++, on the other hand, has a heavy emphasis on types.

A ``typical C programmer"" writes ``int *p;"" and explains it ``*p is what is the int"" emphasizing syntax, and may point to the C (and C++) declaration grammar to argue for the correctness of the style. Indeed, the * binds to the name p in the grammar.

A ``typical C++ programmer"" writes ``int* p;"" and explains it ``p is a pointer to an int"" emphasizing type. Indeed the type of p is int*. I clearly prefer that emphasis and see it as important for using the more advanced parts of C++ well.

The critical confusion comes (only) when people try to declare several pointers with a single declaration:

int* p, p1; // probable error: p1 is not an int*

Placing the * closer to the name does not make this kind of error significantly less likely.

int *p, p1; // probable error?

Declaring one name per declaration minimizes the problem - in particular when we initialize the variables. People are far less likely to write:

int* p = i;
int p1 = p; // error: int initialized by int*

And if they do, the compiler will complain.

Whenever something can be done in two ways, someone will be confused. Whenever something is a matter of taste, discussions can drag on forever. Stick to one pointer per declaration and always initialize variables and the source of confusion disappears. See The Design and Evolution of C++ for a longer discussion of the C declaration syntax.


C 語言設計的本意並不是把「int*」作為類型聲明。它的設計本意是解一個方程,

int ....

讓 .... 的類型是 int。也就是 *ptr 的類型是 int。從而反推出 ptr 是 int 指針。

解方程的語義,才是

int *pt, *pt2;

的寫法的由來。

函數指針也是這樣,

int (*func)();

最早調用是必須寫成 (*func)() 的。後來變成寫 func() 也可以了。但是本意是解方程,(*func)() 表達式是 int 類型。

後來 C++ 加了 搞亂了這個規矩。但是為了對 C 兼容很多文化還是保留下來了。

我自己還是寫成 int* ptr 的。


比如這個

int* a, b;

你以為是int* a; int* b;

但實際上是

int* a; int b;

但是!

解決這個問題最好的的辦法,是絕不在一句話中定義多個變數。


兩種寫法都是等價的。

c語言聲明的標準是:

declaration-specifiers init-declarator-list;

其中declaration-specifiers是extern,static等修飾符加上char,int等基本類型,init-declarator-list是

變數名加上*, [], ()等修飾符。編譯時會先解析出類型,所以對於int* var0, var1, 你看到的是(int *) (var0), (var1), 編譯器看到的是(int)(* var0), (var1)。又因為編譯過程中空白字元是被忽略的,所以不僅int* var0, var1和int *var0, var1是等價的,int * var0, var1和上面兩種寫法也是等價的。事實上,你可以添加任意個空白字元。

但是,int* ptr的寫法容易導致認為int*是基本類型,從而認為int* 後面的變數都是這個類型。舉個例子:int* a, b。初學者很容易誤認為a,b都是指針,但實際上只有a是指針。

而int *ptr的寫法則不容易產生混淆。在聲明int *a, b中,*a, b都是整數型。所以a是整數指針。


這樣寫的人通常都喜歡把一大堆變數定義在一行裡面,which is不好的。


只是補充一點,這確實可能是C/C++設計考慮欠缺的地方。至於為什麼建議"*"靠後,primer上給了充分的理由,我不多說了。

其實題主所說的是合理的,記得也看到有提議說所有的類型相關的都前置,標識符都後置。比如函數指針就可以寫成`void (*)() pointerToFunction`。只是C++確實沒那麼做。不過,也可以看到,java在設計的時候就考慮到了這點,數組的定義成了`sometype[] array1, array2;`。個人覺得歷史遺留因素233。


我把C語言之父的《C程序設計語言》請來了,拍了指針這節的內容:

這裡就可以看出一些端倪了。

【*】是運算符,所以它的正確使用是作用在操作數上【而不是和int類型組合】,這在第二幅圖片也有說明即【表達式*ip】。

因此,int表示的是【*ip】這個表達式的類型。從表達式【*ip】反向推出未使用*操作的ip是個地址。

私以為,比較規範的寫法就是 int *ip這種形式,全書也確實全是這種寫法。


其實這個並不是必須的,但是這樣寫有一個好處:

我們比較一下int *ptr, a和int* ptr, a你就會發現視覺效果上的區別了,特別是對於很多新手來說,會誤以為int*是一個跟int,bool類似的一個東西


我是int* ptr黨,我習慣把這個作為【int型指針變數ptr】來理解,

這樣函數參數和返回值就是int* foo(int* a),

統一的格式多好看,另外不推薦同一行定義多個變數。


這和花括弧同行還是換行的問題有什麼區別嘛。。我個人習慣int* ptr;的寫法。我也從來不會把多個變數申明寫在一行里。但是就算把多個變數申明在一行里然後發生誤用,現在的C/C++編譯器也都是會報錯的啊。


《C++ primer》(第五版)中說明了


Declarations (cppreference wiki)

Overview of Declarators (msdn library)

不知道你習慣看cppreference wiki還是msdn,所以都貼上了。


int * ptr;


現在無論go還是rust,都把*放前面了,所以就是C當初設計的錯誤。


int* ptr = a;
我就喜歡這樣寫啊 我一直把指針理解成為一種數據類型啊

否則的話怎麼理解typedef int* pint;


這麼糾結啊,還是 typedef 成 LPVOID、LPSTR 這樣的形式吧……


因為C語言在設計的時候比較早,很多理念還圖樣,比如認為*ptr應當行為像其所指物一樣。


因為我國法律不讓燒死異教徒


int*不是類型,int才是類型,*是操作符,這個設計邏輯我懂

但既然這樣,就不要再搞個int* p以後,decltype(p)是int*,這自相矛盾我看著很累啊

更別說比如typedef int* intptr了,這不是類型?

覺得int *p, *q好看的,難道不覺得這個星號在各種邏輯下總是格格不入無法統一嗎?

難道還會比這個更好看?

using intptr = int*;

intptr p, q;

對了,用int*,或者intptr這樣的寫法還有個好處——我可以全局搜索我工程里有多少個特定類型的指針變數

所以,還是把int*當做類型吧。頂多就是不配合using或typedef時不能int* p,q

但把變數連續聲明寫在同一行,這燒死不為過吧?

————————————

解釋下為何要燒死

1、寫在同一行,如何初始化?變數不初始化直接用,萬一用出事誰負責?或者都寫初始化,一行代碼戳穿屏幕咯?

2、別和我說多餘的初始化浪費性能——連多餘初始化都優化不掉的編譯器活該倒閉

3、請問,全部寫在一行的變數,我該怎麼寫注釋?不過這樣寫的都習慣int a,b,c,d; int *p,*q,*r,*s的命名風格了,要燒死也輪不到寫注釋的來燒


推薦閱讀:

c語言b++<15是b和15比,還是b+1和15比?
C語言中 *p++ = *p 是如何工作的?
C/C++中++符號的運算順序是怎樣的?
C 語言的內存管理如何比 C++ 的 RAII 靠譜?

TAG:編程語言 | CC |