プログラミング

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)

前回の続きで、国土地理院の「国土数値情報」っていうオープンデータで遊んでいます。独立した記事なので前回のは読まなくても良いです。 やりたいこと 国土数値情報で提供されている「行政区域データ」は、市町村 …

国土地理院の地図データをUnityで読みたい(願望)

なんかgoogleのAdSense通ったんで有益な情報載せないとなって。 国土地理院のオープンデータ 国土地理院が公開している(正確には国土地理院のデータを利用して国土交通省国土政策局国土情報課が公開 …

【Unity】GPUを使ってパンツを隠すスクリプトができた

かわいいスカートを履きたい!でもパンチラしたくない! それは誰もが抱く夢です。もちろん、3Dモデルだってパンチラしたくないと思っているハズです。 というわけで偉大なる先人がいます。 Unityでパンツ …

no image

[python]Windows環境でsubprocessするときは文字コードに気をつけて

pythonは内部の文字コードと実行環境の文字コードが色々絡み合っていて、いろんなところで悪さをする。 特にWindows環境だと、内部はUTF-8で動いているのに実行環境はShift-JIS(正確に …

no image

UnityのCompute Shaderに線分と三角形の衝突判定をさせる

はじめてCompute Shader使ってみた。でもあまり性能は出ないのでただの失敗の記録です。 まず元のアルゴリズムはコレ。 線分と三角形の当たり判定 – 富士見研究所 で、これをまず三角形の表裏問 …