プログラミング

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言語なんてあえて触ろうとせず、他の言語からとっつく方があなたの身と健康のためになると、と言っておきましょう。

-プログラミング

執筆者:

関連記事

no image

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

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

no image

Google Apps Script(GAS)で自宅サーバーの死活監視をする

もくじ1 前置き2 概要3 できあがり3.1 GAS側3.2 自宅サーバー側4 解説5 蛇足1 ログを取る6 蛇足2 サーバーをタイマ起動させて監視 前置き 自宅サーバー使ってますか? 最近もう流行ら …

no image

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

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

no image

暦の面倒臭さと和暦の元号カレンダーを作った話

もくじ1 前書き2 そもそも暦とは3 暦をどう捉えるのか3.1 1000年前の今日はいつ?4 対応カレンダーの必要性4.1 聖徳太子が生まれたのは何日前?5 対応カレンダーの作り方6 おわりに 前書き …

no image

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

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