一回も披露したことのない豆知識

C言語でint main(int argc, char *argv[])とメイン関数を宣言します。

2番目の引数はC言語の文法的にいうと文字列へのポインタの配列だとおもいますが、一般的な関数でこの引数に値を渡すとすると、以下のように宣言されたポインタ配列を渡すことになるとおもいます。

・宣言
char *pa[];
・関数への渡し
func(pa);

話が元に戻りますが、main関数でもらう場合は、プログラム外部から与えられた引数は(正確に言うとアドレス)、メモリ上ではC言語で書かれたexeファイルの外から実行時にプログラムファイルのメモリ上にコピーされるのでしょうか?

自分でもうまく表現できないのですが、
・コマンドプロンプトで引数を与えて実行
        ↓
・プログラムファイルのメモリ上に引数がロードされる
ということでいいんでしょうか?

自分でもなんだかうまく表現できないので、お暇な方でよろしいので、気が向いた人、回答ください。

よろしくお願いします。

A 回答 (5件)

★ちょっと昔話。


・Windows より前の OS MS-DOS では、プログラムが実行されるとメモリ上に存在する
 EXE ヘッダにコマンドラインの文字列と文字数が格納されます。
 そして、C 言語で作成されたプログラムは main() 関数を実行する前にスタートアップ
 ルーチンという処理が行われます。この処理の中に EXE ヘッダに存在するコマンドライン
 文字列のコピーを作ります。その後、スペースで区切られた引数を char *argv[] に
 セットしてから main() 関数が呼び出されます。
・よって、まとめると
 (1)コマンドラインから実行
 (2)プログラムをメモリ上にロード(EXE ヘッダに引数文字列がセットされる)
 (3)スタートアップ処理で EXE ヘッダから C 言語のグローバル変数領域に引数文字列をコピー
 (4)コピーされた引数文字列をスペース文字で区切って char *argv[] 配列にセット
 (5)main() 関数に char *argv[] と区切った引数の個数を argc で渡す
 ↑
 簡単に説明するとこんな感じになります。
・引数文字列はコピーしたものを *argv[] で使うため EXE ヘッダにある引数文字列は
 書き換わりません。→正しくは EXE ヘッダにある引数文字列は書き換えてはいけない。
・上記のは MS-DOS という OS の話です。でも Windows のプログラムも同様な処理を行っている
 と思います。EXE ヘッダ(PE情報)があるので。MS-DOS 時代よりも PE ヘッダが複雑でサイズが
 増えていますね。この PE 情報の資料がほとんど見つかりませんね。英語サイトならありますが…。

最後に:
>・プログラムファイルのメモリ上に引数がロードされる
 ↑
 プログラムファイルのメモリ上(EXEヘッダ)に引数文字列がロードされる
 その後、プログラムのグローバル変数領域に引数文字列がコピーされる
 そして、コピーされた引数文字列をスペース文字で分割される
 そしたら main() 関数の char *argv[] として引数文字列が渡される
 という順になります。
・ちなみに Windows API 関数に引数文字列を取得する GetCommandLine() があります。
 これは多分、EXE ヘッダの引数文字列から直接ポインタで取得しているような気がします。
 理由は、この関数で取得した引数文字列は書き換えないようにという注意書きがあるので。
 でも、本当のところはよく分かりませんが…。注意書きを信じてコピーしてから使いましょう。
・他の OS については詳しく知りませんので 昔の MS-DOS、そして Windows 系で回答してみました。
・以上。

参考URL:http://wisdom.sakura.ne.jp/system/winapi/win32/w …
    • good
    • 0
この回答へのお礼

どうも、大変ご丁寧な解説ありがとうございます。

自分は、一応プログラム暦(アマグラム暦?)6年になります。コンピュータの内部動作とかまでようやくりかいできるようになり、今回、このような質問をした次第です。

その上でOh-Orange様のご回答は非常に参考になりました。WindowsでもUNIXでもいいのですが、とにかく内部的な動作がしりたかったのです。それで、Windows自体のCプログラムの呼び出し具合を書いていただいたので、この上ない、私自身のありがたい知識となりました。

MS-DOS時代からの方でいらっしゃるんですね。私はほとんどWinXPですので、昔の技術も興味あります。UNIXとか必死で勉強しています。

今回は大変ご丁寧な回答誠にありがとうございました。非常に勉強になりました。感謝しきれないくらいです。ありがとうございました。

お礼日時:2007/06/23 17:24

ホスト処理系では、最初にmainが呼び出された後のことしか、規格上は扱われていません。

つまり、それ以前のことは処理系が勝手に決めることですので、一般論で語っても意味ありません。

ちなみに、先ほど「最初に」と書いたのは、mainを再帰的に呼び出すことも可能だからです。その場合は、アプリケーション側でどんな風にメモリを割り付けるかによります。
    • good
    • 0
この回答へのお礼

どうもありがとうございます。

処理系によるんですね。今回は色々なかたのお話をお伺いし、OSがどの辺までCプログラムなどを扱うのかがなんとなく分かった気がします。今までは、OSとアプリケーションの境界線が漠然としていたために、少し疑問におもっていました。

しかし、皆さん、お詳しいですね。どこで、勉強するんですかね・・私自身書店などで結構立ち読みするのですが、全然、その辺の知識が身に付きません・・

今回は勉強になりました。本当にありがとうございました。

お礼日時:2007/06/23 17:27

#2さんの通り、たいていプログラムの起動時に _CRTStartup() とかいった名前の関数が呼ばれて、そこで、コマンドライン引数などの解析(argc,argvへの格納)をして、main()を呼び出すって感じの処理をすしてます。


例えば、いにしえのDOSの時代には、
アドレス 80h にコマンドライン引数が格納されていました。
http://www5c.biglobe.ne.jp/~ecb/assembler2/1_1.h …
    • good
    • 0
この回答へのお礼

どうもありがとうございました。

#2様のおっしゃるとおりなんですね。私は、諸事情で大学すら行っていないので、深い知識は全然分からないので、ここの皆さんの知識には驚かされるばかりです。参考URLも見させていただきましたが、どこでそういったものは、見つけてくるのですかね・・

なにしろ、困ったらここで聞くしかないので。。

どうもありがとうございました。MS-DOSの頃のような基本的なことから勉強したいです。でも、その環境作りも今じゃ難しいですよね。なんとか、しがみついて、勉強していこうとおもいます。

目標は80歳で名を挙げることです・・

お礼日時:2007/06/23 17:33

C言語の規格では、mainエントリ関数に渡されたコマンドライン文字列は書き換え可能ということになっています。


#元の文字列の長さを超えて書き込むとどうなるかは分かりません。

ということから、mainに来る前にメモリが確保されて文字列がコピーされている、と考えることができるのではないでしょうか。
    • good
    • 0
この回答へのお礼

どうもありがとうございます。

isle様の教えていただいたことから推測すると、確かに、mainに来る前に文字列がコピーされていると考えることが、確かなようですね。

C言語の知識は、つけようと思えば、いくらでも本に載っていますが、その辺のOSとのやりとりというか、OS内部部分まで関わってくると、なかなか、知識の身につけようがないですね。まして、昨今のパソコンOSは、非常に高度みたいですし。。なにか、MS-DOS時代がうらやましくなりもします。

ご回答ありがとうございました。参考になりました。

お礼日時:2007/06/23 17:30

実は、厳密に言えば、C/C++のプログラムで最初に実行されるのは、main() ではありません。


引数の処理や、グローバル変数の初期化など、前処理をするプログラムがあります。
このプログラムが動いて、準備がすべて整った後で、main() という関数がこのプログラムから呼び出されます。

コマンドラインの引数をどのようにして渡すかは、コマンドプロンプトやOSの取り決めになります。その取り決めを理解して、main() がわかるようにセットアップするプログラムが、一番最初に動くということになります。
そういう小さな(小さくないかも)プログラムが、各コンパイラの各OS用に準備されています。これは、ユーザーには見えないうちに処理されてしまいます。

いわゆる「組み込み」の世界で、OSなど無いという段階では、main() を呼ぶまでのスタートアップルーチンも、はっきり見えますが。
    • good
    • 0
この回答へのお礼

どうもありがとうございます。

考えてみれば、実行ファイルというのは、機械語のレベルですもんね。C言語の文法で考えることがおかしいですね。

AsanoNagiさんが教えてくれたことは、理解できました。たかだかプログラム言語を扱ったところで、コンピュータ全体の動きにかかわることを考えようとしたのは、あさはかだったですね。

ん~。実に難しいですね。掘っても掘っても見つからない温泉のように、なかなか、コンピュータの底まではたどり着けませんね。組み込みをやればわかるということなので、いずれやったとき?は覚えておきます。

ご回答ありがとうございました。大変参考になりました。

お礼日時:2007/06/21 17:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!