プログラミング

C言語のポインタに関する補足説明

投稿日:2018年3月11日 更新日:

前回、C言語のポインタに関する解説記事を書きまして、そこそこの反響を貰うとともにいくつかの指摘を受けました。
前回の記事では幾つか「ウソではないけど真実と違う」記述がありまして、その点を補足としていくつか説明します。
今回、初学者向けではなく中級者以降の人でないとナンノコッチャ度が高いのでお付き合いください。

仕様と実装のごちゃまぜ

前回の記事で行った最も激しいダマシがこれです。
C言語とは仕様であり、実装はコンパイラに依存します

前回、暗黙的にgccを利用して実験をしており、特にアドレス周りの記述はLinuxの64bit環境を前提としたコーディングが成されています。
しかし、究極的にはポインタがメモリアドレスであることすら仕様には明記されていません
ポインタ=アドレス、というのは、一部のコンパイラが勝手に決めた仕様に他ならないわけです。

特に、現在ナマのC言語が求められる局面というのは、一部の低レイヤーな挙動を制御するシステムに限られます。
具体的にはマイコンであるとか、ハードウェアの組み込みソフトであるとか、ファームウェアであるとか、ミドルウェアであるとかです。
つまり、皆さんが普段触れているようなWebアプリやスマホアプリ、Windows用プログラムの大半はC言語では書かれていない。
もはやニッチな分野でしか使われない特殊言語な訳です。
で、特殊言語ゆえに、環境ごとに実装が大きく異なります
なので、「C言語」と一口に言っても、その実装は様々であり、もはや「特殊な実装である方が普通」と言っても過言ではないわけです。

「コンパイラ」を便利に使いすぎている

前回、「コンパイラ」という言葉に全てを任せ過ぎています。
実際、gccにおいて「コンパイラ」の役割は以下のように細分化できます。

  • プリプロセッサ(#includeなどの展開)
  • コンパイラ(アセンブリへの変換)
  • アセンブラ(アセンブリから機械語へ変換し、オブジェクトファイル(.o)を生成)
  • リンカ(オブジェクトファイルを束ねて実行可能ファイルを作成)

これらを全てまとめて「コンパイラ」と呼称してしまっているわけです。

まぁ実際、gccはコマンド一つでソースファイル(.c)を実行可能ファイル(.outとか.exe)にできるわけですし、初学者が上記の呼称を意識する必要はないんですが。中級者以降なら分けられているのは知っておかないといけませんね。

なので、全てを「コンパイラ」が決めているというのは、そこそこ強烈なウソなわけです。

物理メモリと仮想メモリの概念の省略

ぶっちゃけ、仮想メモリというのはOSの用意する機能であってC言語が意識するところではないです。

ただ、実際に緑と黒のゲジゲジに乗っているのは物理メモリであり、Linuxで実行するファイルでポインタが指すアドレスは仮想メモリであります。
そして前回の記事で書いた「0x7fffffffe494」とかいうアドレスは全て仮想メモリです。
なので実際は「0x7fffffffe494」という場所が物理メモリ上にあるわけではなく、プロセスが持つ仮想メモリ空間上のアドレスなわけです。
実際に利用するときにはOSによって物理メモリへのマッピングが行われますが、物理メモリ上のアドレスというのはそれこそ誰も気にする必要のないところです。脆弱性を突きたいわけでなければ。

スタック領域とかヒープ領域とかうんぬん

変数のアドレスの場所、というのは宣言の仕方によって変化します。
ローカル変数であれば基本的にスタック領域に置かれると思いますが、グローバル変数だったりstatic宣言されていたりするとスタックではない領域に置かれることもあるでしょう。その場合、OSのメモリマッピングに依存して場所が決まることになります。多分。

また、スタック領域が絶対的にアドレスを決め打ちできるという保証もありません。スタック内でのメモリ配置はコンパイラによって行われますが、スタック領域がどこに取られるか、というのは正直自分は詳しくないです。
メモリマップを見る感じだとvdsoがスタックの前後に入りがちですがどういう法則なのやら。
またmallocコマンド等でヒープ領域を動的に確保した場合、それこそ動的に確保しているのでアドレスがどこになるか、というのは完全に未知数です。

とにかく変数のアドレス参照は相対的に行われるので、絶対アドレスを指定した参照なんて普通やっちゃいけないです。

そのため、メモリのアドレスをコンパイラが決めている、というのはいろいろな意味でウソのある表現だったわけです。

おわりに

前回の記事はなんだかんだ初学者向けのため、「本当はこうだけどちょっとウソをついておこう」という記述がちらほらありました。
その辺ツッコミを入れている方が多く、みんなマジメに読んでいるんだなぁって思いました。
そういう人は既にポインタについて詳しいハズなので、たのしくツッコミを入れてもらえれば良いです。

また、プログラミング初学者の人はC言語なんてあえて触ろうとせず、他の言語からとっつく方があなたの身と健康のためになると、と言っておきましょう。

-プログラミング

執筆者:

関連記事

GeoJSONで市町村境界をマージして都道府県境界にしたい(その1)

前回の続きで、国土地理院の「国土数値情報」っていうオープンデータで遊んでいます。独立した記事なので前回のは読まなくても良いです。 もくじ1 やりたいこと2 問題の整理3 「穴」の考慮4 つづく やりた …

GeoJSONで市町村境界をマージして都道府県境界にしたい(その2)

GeoJSONのPolygonをマージしたい第2回です。 前回、純粋な多角形の統合ではなくて、領域が被らない多角形の統合になるのでグラフ問題として解くことができるという説明をしました。 今回はどうやっ …

no image

BlueskyのAPI制限が厳しくなったぞ

以前、Blueskyのbotを作る記事を書いたんですが、そのbotがいつの間にかひどくエラーを吐くようになっていました。 で、調べたところ、API制限が厳しくなっていると。 詳しく言うと、Rate L …

no image

[C言語]スペースを大量に入れるとバグが直るコードを書いてみた

↓こういうツイートがバズっていたので、実際に組んでみた。 修士の頃、授業の課題でC言語書いてる時にどうしても謎のエラーが出て困っていた。それを見たSE経験(金融系)がある社会人大学院生の同期の女性が「 …

SHOWROOMのガチイベをGoogleスプレッドシートでグラフにしよう

もくじ1 まえがき2 みほん3 だいじな注意事項3.1 Google Apps Scriptの制限3.2 SHOWROOMの仕様4 てじゅん4.0.1 1.4.0.2 2.4.0.3 3.4.0.4 …