質問: *pointer;`の`*`は、`pointer`アドレスに格納された値を取り出すこと示すものです。 ここで私が抱く疑問は、 `int *pointer`の表現方法として、`*`を使わない方法をなぜ取らなかったか、できない理由があったのかということです。 例えば`const`や`static`のように、`int`の前に`point`とか書く方法もあったのではないでしょうか。 また、 ポインタ`pointer`は、`*pointer`で中身を指し示し、`pointer`でアドレスを表現しますが、 これ、どう考えても逆の方が良かったんじゃないの?って思います。 逆にすると、何かしら弊害があるのでしょうか。 まだまだC言語について知識が足りないため、至らない点あるかと思いますが、 お付き合い頂ければ幸いです。
回答: 歴史的なことは初期のCコンパイラーがヒントになるかもしれません。下記はその紹介記事です。 本の虫: デニス・リッチーによって書かれた最初のCコンパイラーがGitHubで公開 この頃には既にポインターが存在していました。しかし、`int **ipp;`というポインターのポインターのような宣言は出来ず、また、通常のポインタの宣言も最初は`int ip[]`と書いていたようです(`int *ip;`という表現も受け付けたようですが)。 以下、私見です。 Cの変数は必ず何らかの記憶域(storage)を持つ実体(object)です(記憶域はメモリ上とは限りませんし、しばしば最適化によって変数自体がなかったことにされることもありますが)。つまり、変数を束縛している実体は変数の記憶域に収まっているということです。JavaやC#の参照型のようなオブジェクト自身であるところの実体と変数の記憶域が異なるような変数はありません。変数と実体が同じであるという構造は、変数への操作が単純なメモリ上のデータ操作に変換できるため、コンパイラも非常に単純な作りにすることができます。 文字列などのシーケンシャルなデータを扱うには配列のような仕組みが必要になります。配列全体を実体とすることは可能ですが、別の変数に同じ配列を見せようとしても、そもそも複数の変数が同一の実体を共有することは出来ませんし、配列全体をコピーすることも非効率です。また、変数とオブジェクトの寿命が必ず一致してしまうということは、コンパイル時に静的に決まる変数では、データを動的に生成・消滅させることが難しくなってしまいます。そこで、ポインターという実体です。配列へのアクセスをポインターのアクセスと同様に扱える(配列とポインターが全く同じと言うことではありません、この二つは厳密に区別されます)ようにすることで、ポインターを介した配列操作を可能にしました。また、`malloc`等で動的に確保した記憶域については、ポインターを介してアクセスすることで、変数の寿命と動的に確保された記憶域にあるオブジェクトの寿命を切り離すことが出来ました。 重要なのはポインターも一つの実体に過ぎないと言うことです。こうして、Cはその言語構造を複雑化することなく、ポインターを用いて強力な表現を可能にしました。当時の技術は今ほどコンパイラや構文解析の研究が進んでいないため、単純であると言うことは極めて重要でした。JavaやC#の参照型ような型を別途用意するような複雑さは取り入れることはしなかったのです(当時、そのような言語が全くなかったのかまではわかりません)。 では、ポインターをどのように表現するのかです。初期のCコンパイラーに見られたように、`*`でポインターが示す先の実体を表現するようにしていましたが、宣言が`int ip[];`という形でした。ポインターと配列は同様に扱えると言うことから、配列の宣言のように書けることはそれはそれで意味があったと思います。さて、`int ip[];`ですが、これは、`int (ip[]);`ともいえます。つまり、`ip`を配列とみなしてその要素にアクセスしたときの型は`int`であるということです。そこから`int (*ip);`つまり`int *ip;`もまた同様に考えられます。`ip`をポインターとみなしてその指し示す先の実体の型が`int`であるということです。これは、宣言ではないところでの`*`と同じような解釈(ポインターの指し示す先の実体という解釈)をしているということです。このようにすることで、構文解析を単純化しようとしたのではないかと推測されます。それが当時うまくいったのかまではわかりませんが。 なお、その後の言語を見るとこの方法は失敗だったと考えられます。キャストやsizeofの引数として`(int *)`という表現が使えるため、宣言においても、あたかも`int *`でひとまとまりの型だと見られてしまうという誤解も生みました。配列は後置になるため、更に混乱の元でしょう。Java等では`int[]`のような型表現を前置におくようにしたのもそれらが理由と思われます(C/C++ユーザーのため、Javaでは後置の書き方もサポートはしていますが)。ただ、最近は型を前置すること自体がよろしくないと考えられており、後置の言語(Go、Rust等)が増えているようにも思います。