W.I.S. Laboratory
menu-bar

C言語


Cのポインタ変数宣言は int *a と int* a どちらが今風なのか

Cのコンパイラは、ポインタ変数を宣言するときに「int *a」でも「int* a」でも同じように扱う。
私自身は「Cのポインタ」というのはポインタ変数であって、Cにはポインタ型という型は存在しないと思っているので、「int *a」と書くことがほとんどだ。
昔から長くCを書いている人のコードを見てみても、このように変数側にアスタリスクを付けて書いている人が多い。
そういう人たちも私と同じ考えなのではないかと思う。
おそらくその根拠は、以下のような書き方をしたときのコンパイラの捉え方だろう。

これをコンパイルすると、ポインタ変数になるのは最初のaだけで、bとcはint型の変数になる。
Cコンパイラにとってポインタ宣言子のアスタリスクはあくまで変数に付くものであって、型に付くものではないのだ。

ただ比較的新しい言語をメインで書く人の中には、Cを書く時に「int* a」と宣言する人が一定数いる。
以前はなんか気持ち悪い気がしていたが、最近はこのほうが新しい書き方に見えてきた。
そう感じ始めたのは、C++で型推論ができるようになったC++11の頃からだと思う。
C++の型推論を使うと、このように書けるようになった。

これで変数aはconst char型のポインタ変数として宣言されるのだ。
ということはこの「auto」というは「const char *」として展開されているわけで、「型推論」というのはその名の通り右辺の内容から左辺の「型」を推論する機能だ。
C++のコンパイラは「char *」を「型」として認識している、ということになる。
C++11からスマートポインタが実用的になったが、このスマートポインタを宣言するときにも型推論はできる。
が、それをしないときでも

このように変数hの前にポインタ宣言子であるアスタリスクは不要だ。
このhは「スマートポインタ変数」ではなく「スマートポインタ型」の変数だ。
つまりC++には「スマートポインタ型」という型があるわけだ。(まあスマートポインタが正確には「ポインタ」ではなくポインタ変数を格納したインスタンスだからといえばそうなのだけども)
こういう背景があるからか、C++を書く人には「int* a」派が一定数いるような気がする。

2010年代になってから、GoやRust、SwiftやCrystalなどの新しい静的型付け言語が飛躍的に普及してきた。
そのどれもが型推論を装備している。

これらの言語は、代入するものがどんな型であっても(例えアドレス値であっても)変数名には何も付けなくていい。
そういえばJavaで配列を宣言するときも、

変数名には何も付けないほうが推奨されている。
「宣言時に変数名に何もくっつかない」というのは、「今風の書き方」なのだ。

そう考えると、Cで「int* a」と書くのは新しい書き方のようにも思える。
ポインタ変数をconst修飾するときも少しキレイに書けるし、新しい言語から来た人にはこのほうが読みやすいかもしれない。

そしてCでも「int*」をtypedefできるし、その場合は下のような書き方ができるのだ。

この場合はa,b,cすべてがint型のポインタ変数になる。
この時のCコンパイラは「int*」(int型のポインタ)を「型」として認めていることになる。
もしコンパイラが「int*型」を認めなかったら、「そんな型はないのでtypedefできない」というエラーで弾くはずだ。
それに、今この時代において複数のワイルドポインタを1行で宣言する必要性があるのかと問われると、正直即答できる自信がない。
「int* a, b;」とうっかり書いてしまって、思いがけずbがポインタ変数にならなかったことが原因でデバッグに苦労する・・ということが、これからのプログラミング人生において起こる気がしないのだ。
言語は生き物だと言われる。
時代とともに変化していく。
それは自然言語でもプログラミング言語でも同じことなのかもしれない。
最近の静的型付け言語からCに来た人たちが「int* a」と書いている理由が少し見えた気がする。


[ 戻る ]
saluteweb