• ベストアンサー

初期化は、main関数の外で行うものなのか

 ルネサスHEWのサンプル・プログラムを見ると、I/Oの初期化、Bセクションのクリア、DセクションからRセクションへのコピーなどを行ってから、main関数に飛んでいます。  これらの初期化はメイン関数の中で行うべきだと思っているのですが、どうなんでしょう。  パソコンでexeファイルを実行した場合、mainに飛ぶと思っているのですが、初期化プログラムに飛んでからmainに飛ぶのでしょうか。  宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.8

回答者の中にもよく分かっていない人がいつようですが.... まず、リセットがかかったときにどのアドレスからプログラムを実行するかはCPUによって異なります. HEWということですが、H8やSHであれば0番地にリセットベクタを格納しますので、そのアドレスから実行されることになります。M16CやM32Cであれば、アドレス空間の最後にリセットベクタを格納します。MIPSなんかは0xbfc00000番地から実行します。このように、CPUによって事情が異なります。 次に、スタートアップの話ですが、Cの規格では、プログラム開始位置が実行される時点では、静的記憶域期間を持つオブジェクトの初期化が完了していなければなりません。これはフリースタンディング環境(OSのない環境)でも同じです。ですので、スタートアップでそうした初期化を行います。 スタートアップでは、静的なオブジェクトの初期化以外に、DRAMやキャッシュの初期化など、ハードウェアの初期化も行います。スタートアップは処理系の一部ですので、そうした処理を書くのは処理系を構築する作業になります。 モニタプログラムなどが存在するシステムでは、こうした処理をモニタがやってくれることもありますが、ハードウェアが変わるたびにスタートアップを書き換える必要がありますので、誰がやるかは別として、ポーティングは組込みでは必須の作業となります。

ricardo_
質問者

お礼

 いつも回答有り難う御座います。 >Cの規格では、プログラム開始位置が実行される時点では、静的記憶域期間を持つオブジェクトの初期化が完了していなければなりません。  そのような規格が有るのなら、納得出来ます。  I/Oの初期化はどうでしょう。組み込みプログラムの説明によると、「ノイズによってI/0の設定が変わるおそれがある。信頼性を上げるため、定期的に再設定した方が良い。」となっています。  I/Oの初期化は、main関数の中で行うのがスマートかなと思うのですが。

その他の回答 (8)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.9

>今までの回答から、パソコンにおいてユーザーが作るのはmein以降と思ったのですが、今回の回答ではスタートアップルーチンもユーザが作ると思うのですが。 昔は全部自分で書いてましたが(スタートアップの簡単なサンプルみたいな物は開発キットに付属してました)、HEWなど統合環境ではマイコンの種類に合わせてHEWがスタートアップを用意してくれますね。 ただ、それを無視して自分のスタートアップを書く事も可能だと思いますが書く必要があるのは疑問です。別に任せても問題ないのでは? 環境によりますが、組み込み系ならスタートアップは自分で用意する場合も多々あります。HEWやWinアプリなどの統合環境やCコンパイラなどは自動的にスタートアップを用意してくれます。 例えばH8でもHEWを使わずにgccを使うならスタートアップを用意する必要がありますね。 http://tokyo-ct.net/usr/kosaka/for_students/H8/3048/h8general_GCC.html

ricardo_
質問者

お礼

 何度も回答有り難う御座います。  いろいろと有り難う御座います。  C言語で出来ないスタックポインタの設定などはスタートアップで行うにしても、C言語で出来る事はmain関数の中で行った方が良いんじゃないかなと思っています。  サンプルを見ると私の考えと違うので、一般的にはどのように行われているのかと思い質問しました。  みなさんの回答を見て、参考になりました。有り難う御座いました。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.7

>C言語では初期値を持たない変数をゼロクリアする約束が有りますが、それはOSが行ってくれて、プログラム開発者は意識しなくていいのでしょうか。 それは言語毎のお約束で、OSがやるべきことではありません。スタートアップルーチンの役割です。 セクションをメモリ空間に展開するのはOSの役割ですが、OSの無い組み込み環境ならスタートアップルーチンやブートローダがその役目を負う必要があります。 Windows実行ファイル「EXE」の謎に迫る http://codezine.jp/article/corner/61

ricardo_
質問者

お礼

 再度回答有り難う御座います。  「http://codezine.jp/article/corner/61​」は参考になりました。  今までの回答を見て、スタートアップルーチンはOSの役目だと思いました。  OSでないとすると、Cコンパイラが自動的に作ってくれる物なのでしょうか。初期値を持たない変数をゼロクリアするスタートアップルーチンはコンパイラが自動的に生成出来るしょうが、I/Oの初期化はユーザが作らないと無理だと思います。  今までの回答から、パソコンにおいてユーザーが作るのはmein以降と思ったのですが、今回の回答ではスタートアップルーチンもユーザが作ると思うのですが。

回答No.6

main() は、「ユーザーが書いたプログラム のうち、一番最初に実行されるもの」です。 これ以前の処理は、その環境(OS とか)に 応じて、処理系が勝手にプログラムをくっつ けます。 これが、スタートアップとか呼ばれるものに なります。 例えば、Cでは、「初期値が省略されたグロー バル変数は暗黙のうちに、0 で初期化される」 という決まりがあります。 これを実現するためには、main() より先に、 「グローバル変数をゼロで初期化する」プログ ラムが動作しなければなりません。 そして、そのプログラムは(暗黙の初期化なので )ユーザーが書いたものではありません。 こういうものが、main() の実行前に行われます。 Hew が main() の実行前に行っている初期化は 「RAM 領域全体を一括してゼロクリアする」と 言うレベルの初期化です。 (上で書いたような、グローバル変数の暗黙の 初期化もこのあたりで実現できる) 一方でC言語で、「実装している RAM領域全 体」を、知る方法はありません。 C言語(というか、ユーザーの書いたプログラ ム)では、「使うつもりの変数を、適切に初期 化する」ということを行うべきです。 これが、main() の実行に先立って、暗黙のう ちに実行される初期化と、ユーザーが書く初 期化の違いです。 さて、CPUは、リセットされると、その CPUに決まった方法で、プログラムの実行 を開始します。 (必ずしも、ゼロ番地から実行を開始するわ けではありません) この位置には、スタートアップルーチンが来る ケースが多いです。 ユーザーが書く main() は、スタートアップ が終了した後に呼び出されるプログラムに過 ぎません。 なお、パソコンのOSでもこのあたりの事情は 同じです。 実行ファイルは、「ローダ」というプログラム でメモリに展開されて、必要な前処理がなされ、 それが終わった後に、ユーザープログラムの 実行開始点である main() などが呼び出され ます。

ricardo_
質問者

お礼

 早速の回答有り難う御座います。  みなさんの回答から、main関数の前にデータ領域の初期化がC言語の規格だと分かりました。 >Hew が main() の実行前に行っている初期化は「RAM 領域全体を一括してゼロクリアする」と言うレベルの初期化です。  HEWのサンプルプログラムは、BセクションのゼロクリアとDセクションからRセクションのコピーを行っています。

  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.5

#3です。 組込みのmain関数は、パソコンのOSと同じと例えれば分かり易いかな? どちらも必要な手続きをしないと、いきなり実行は不可という意味で同じです。

ricardo_
質問者

お礼

 再度回答有り難う御座います。

noname#29459
noname#29459
回答No.4

基本的に、Cのmain()関数の前に、スタートアップルーチンが走ります。 ルネサスHEWがなにかは、存じませんが、スタートアップルーチンで、どこまでやるかは、その言語処理系(OS)で、決まります。

ricardo_
質問者

お礼

 早速の回答有り難う御座います。  みなさんの回答を見て、組み込みマイコンの場合スタートアップルーチンがOSに相当するらしいと分かって来ました。

  • black2005
  • ベストアンサー率32% (1968/6046)
回答No.3

どんなCPUでも、ブート後は0番地から実行を開始するのをご存じですか? 組込みのスタートアップルーチンは、パソコンのBIOSに相当すると言えば分かりやすいかな? パソコンだって、いきなりOSは走らない(走れない)でしょ? >パソコンでexeファイルを実行した場合、mainに飛ぶと思っているのですが、初期化プログラムに飛んでからmainに飛ぶのでしょうか。 既に動作中のOS上で実行するアプリケーションと組込プログラムは、実行開始時点の状態が全く異なります。 比較する事自体ナンセンス。

ricardo_
質問者

お礼

 早速の回答有り難う御座います。 >どんなCPUでも、ブート後は0番地から実行を開始するのをご存じですか?  最後のアドレスにベクタアドレスが書いて有るCPUも有ったような気がします。68000だったかな。 >組込みのスタートアップルーチンは、パソコンのBIOSに相当すると言えば分>かりやすいかな? >パソコンだって、いきなりOSは走らない(走れない)でしょ?  OSがBIOSを呼ぶと思っているのですが、そうでは無いのですか? >既に動作中のOS上で実行するアプリケーションと組込プログラムは、実行開>始時点の状態が全く異なります。比較する事自体ナンセンス。  組み込みモニタでプログラムをロードしたり実行したりします。このモニタが、パソコンのOSに相当するのでは?

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

この辺の意識は「組み込み」な人とそうでない人の間には差があるかもしれない. 順番を変えますが, 「パソコンでexeファイルを実行した場合」には, 「カーネルから直接 main関数が実行される」ことはありません. なぜなら, main関数の実行の前後に「定型的にしなければならないこと」があるからです. 例えば main関数の開始直後から printf が使えるわけですが, そのためには構造体 FILE を適切に初期化する必要があります. しかし, そんなことを毎回 main に書かせる (あるいは初期化ルーチンを main から呼び出させる) よりも, 「main の前後にしなければならないこと」を行うルーチンを作り, そこから main を呼び出す形にした方が便利です. つまり, 処理系の作成者においては「どんなプログラムでも必ず実行される」ことを前提にできますし, プログラムの作成者にもそのような「プログラム本体とは直接関係ないこと」を書かなくて済むからです. 一方, 組み込み方面だとおそらく意識は違うと思います. つまり「自分の書いたことだけを実行し, 書いていないことは実行しない」のが動作として正しい, という考え方があると思います. そう考えれば「これらの初期化はメイン関数の中で行うべき」というのは正論です. これに対し, 「定型的に行うことをいちいち書くのは面倒」あるいは「書き忘れると痛いのでいや」というのももちろん 1つの考え方たり得ます. そして, そう考えれば「初期化を行ってから改めて main に飛ぶ」ということも十分な意味があります.

ricardo_
質問者

お礼

 早速の回答有り難う御座います。  C言語では初期値を持たない変数をゼロクリアする約束が有りますが、それはOSが行ってくれて、プログラム開発者は意識しなくていいのでしょうか。  exeファイルに何か情報が書いてあり、OSがそれを見てゼロクリアしてくれるのでしょうか。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.1

>これらの初期化はメイン関数の中で行うべきだと思っているのですが、どうなんでしょう。 スタートアップルーチンで初期化しなければならない物は、スタートアップルーチンで初期化すべきです。特にセクション関係はアセンブラで無いと記述できないのでは? >パソコンでexeファイルを実行した場合、mainに飛ぶと思っているのですが、初期化プログラムに飛んでからmainに飛ぶのでしょうか。 パソコンのexeもスタートアップルーチン経由でmainに飛びます。

ricardo_
質問者

お礼

 早速の回答有り難う御座います。 >特にセクション関係はアセンブラで無いと記述できないのでは?  普通はそうだと思いますが、HEWでは __sectop, __secend と言う演算子が用意されています。 >パソコンのexeもスタートアップルーチン経由でmainに飛びます。  そうですか。例えば編集するテキスト名を指定してエディタを起動した場合、main(int argc, char *argv[]) のパラメータにテキスト名を入れ、エディタソフトのmainを呼ぶと思ったのですが違うのですね。

関連するQ&A

  • main関数の戻り値

    C言語のmain関数の戻り値はint型ですよね。 私もそういう決まりだと思って守ってきました。 しかし、「mainが戻り値を返すって、どこに返すの?」ということが、私は理解できていません。 私が調べたところでは、「ホスト実行環境」という言葉がこの問題に関係あるようですが、この言葉の意味はよくわからないですし、似た言葉で「ホスト環境」ということばがあるのですが意味も関係もわかりません。 これらは、OSとは違うと思うんですが、自信はありません。 それでも、ない知識を振り絞っていろいろ考えてみると、次のようなことらしいのですが、正しいでしょうか。 ・OSはプログラムの実行に先立ちホスト実行環境を作る。 ・静的記憶域のオブジェクトを初期化するのはホスト実行環境である。 ・関数が、main関数を呼ぶことは可能である。(以下では、main関数が関数から呼ばれる場合は除く。) ・main関数を呼ぶのは、ホスト実行環境が行なう。 ・main関数の中のreturnによってプログラムが終了するのと、exit関数でプログラムが終了することに違いはない。 ・main関数の戻り値は、ホスト実行環境に返される。 ・returnによってホスト実行環境に返される値は、int型である限りなんでもよい。 ・exitによってホスト実行環境に返される値は、int型である限りなんでもよい。 ・必ずexitで値が返されるならば、main関数の中にreturnはなくてもよい。 main関数からの戻り値をどうしようと構わないんだと思うんですが、皆さんの経験の中で、実例としてこういうふうに使われる、というのは何かないのでしょうか。 (ホスト実行環境に値が返される、といっても無視するのでは意味はないと思うのです。 その値の使用例としては、 0が返ってくると「プログラムは正常終了しました。」と表示するとか、0以外の値が返されると別のプログラムが走るとか、 そういうことだと思うんですが。)

  • NORTiプログラムのROM化

    OS    :NORTi4 1.18a 開発環境 :HEW4 コンパイラ:SHC C/C++ Compiler ver.9.01 CPUボード :AP-SH4A-0A(アルファプロジェクト社製) 1.ROMにプログラムを焼く 2.パワーオンリセットでバスの設定、ROMとSDRAMを使用可 3.ROM上の初期化関数へジャンプ 4.初期化領域をゼロクリア、初期化領域データのメモリコピー、  ROM上のプログラムをSDRAMへコピー 5.Cのmain()関数を呼び出し(RAMへジャンプ) http://www007.upp.so-net.ne.jp/SY-Firm-Ware/hew/hew.html http://hitachisoft.jp/Products/SH-C/support/faq_21.html 上記のサイト等を参考に行いましたがうまく動きません。 どこで問題が起きているか確認できるようにモトローラSフォーマット ファイルではなくabsファイルをROMに書き込みデバッグしながら行っています。(ROM上でのデバッグはよくないようなのですが、原因がつかめないので。。。どうしようもなくて。。) リセットベクターからいきなりGOするとmainに飛んでくれないんです。 付属のサンプルプログラムで試した時もいきなりGOするとmainにいってくれません。 ステップ実行で1ステップづつ実行していってmainループの中を一通り動かしてからGOすると動くような状況です。 初期化領域のゼロクリアや、データコピー、プログラムのコピーはちゃんと行われています。 何が悪いのかわからず困っています。 宜しくお願いします。

  • main関数内のローカル変数について。

    main関数内でローカル変数は使用しない方が良いのでしょうか? 例えばmain関数内でループ処理(無限ループ)を行なう場合、 プログラムを終了するまで、ローカル変数は解放されないように思います。 なので、プログラム実行中は常にスタックに積んである状態になってしまいます。 この場合main関数内の変数は静的変数にするのが望ましいのですか?? よろしくお願いします。

  • "main"について

    "main"についての質問です。 今まで私は"main"というのはC言語の予約語の一つだと思い込んでいましたので、"main"は変数名には使えないと思っていました。 ところが以下のようなプログラムを実行してみると問題なくコンパイル出来る上に問題なく実行できました。 int main(void) { int main; main = 300; printf("%d\n", main); return 0; } 確かに入門書などを見直してみると、予約語の中に"main"はありませんでしたし、関数名が変数名として使えないとは書いて無いように思います。 でもなんだかしっくりきません。(^^;) 関数ポインタを使う際などは、変数=関数名(p = myfunction)などと書いたりするので、main関数が格納されているメモリなど変なところを書き換えたりしている可能性があるような気がしたのですが、うまく確認する方法を思いつきませんでした・・・。 ただたんに変数が優先的に処理されているだけというのなら納得するしかないのですが。 どなたか詳しい方がいたら教えてください。よろしくお願いします。

  • init関数の意味

    C言語をメインで学習しているのですが、 よく変数の初期化のためにわざわざinitという関数を作って、それをmainの中で実行しているサンプルを見ます。 これだと変数はグローバル変数として宣言しなければいけませんし、init関数なんて作らなくても普通に変数をmainの中で宣言して、同時に初期化すれば良いのではと思ってしまいます。 一体何のためにわざわざinit関数を作るのでしょうか? また、別の質問なのですが、ポインタを使えばグローバル変数を使う必要はないような気がしていて、逆にポインタを使うのが面倒なときでも、グローバル変数で代用できてしまう気がします。 それぞれを使うときのメリット、デメリットがあれば教えていただきたいです。

  • プログラムがmain関数から始まらない??

    C言語初心者です。よろしくお願いします。 return文について勉強している途中だったのですが、次のプログラムを実行してみたところ、わからないことが出てきたので質問させていただきました。(ほとんど自分で作ったプログラムではないです) #include <stdio.h> /* 関数a()はintを返すと指定 */ int a() {     if (1) {          /* ここで関数a()は終わります */          printf("yes1\n");          return 300;     }     pritnf("yes2\n");     /* ここは通りません */     printf("this is a()\n");     return 10; } int main() {     int i;     /* 関数a()の返り値を変数iに代入します */     i = a();     printf("i = %d\n", i);     return 0; } このプログラムの出力結果は yes1 i = 300 となるのですが、 1.以前「main関数からプログラムは開始する」というようなことを学習したのですが、このプログラムではyes1が出力されていることからa関数からプログラムが始まっていませんか? 2.a関数のif文の中のreturn 300;でプログラムが終了しないのはなぜですか? 知識のある方、どうか教えてください。 よろしくお願いします。 ※ このプログラムを表示させる際、Tabキー及び半角では適度な空白スペースを作ることができなかったので、プログラムを見やすくするための空白スペースは全て全角スペースで作ってあります。(もしかしたら普通に表示させる方法があるのかもしれませんが、わかりませんでした。)

  • main関数終了時のreturnの意味は?

    質問の題名通り、main関数終了時のreturnの意味が知りたいです。いつもは参考書に書いてある通り、return 0とやっていたのですが、参考書のサンプルプログラムでreturn 1というのがでてきた為、少し混乱しました。 参考書に説明が載っていないのでmain関数内でのreturnの意味をご教授願いたいです。よろしくお願いいたします。

  • コマンドラインのオプションの読み取り

    C++で、引数に/オプションで処理ごとに実行するプログラムを書きたいのですが、具体的にmain関数でどう書けばよいのでしょうか? スマートの方法が知りたいです。 sample.exe /test=1 aの関数を実行 sample.exe /test=2 bの関数を実行 sample.exe /test=3 cの関数を実行 int main(int argc, char**argv) { ... ここの処理? } void a(){ print "A\n"; } void b(){ print "B\n"; } void c(){ print "C\n"; }

  • C言語 main関数とsum関数の記述順について

    はじめまして。 【苦しんで覚えるC言語】(Web版)でC言語を学んでいる初学者です。 【第1部:C言語基礎編】>【関数の作り方】>【自作関数を作る】の部分(http://9cguide.appspot.com/11-01.html#S2)でつまづいています。 下記のような、1から100までの数字の合計を表示するプログラムが例題として取り上げられています。 しかし、ここが理解できないので、次の【プロトタイプ宣言】に進めずにいます。 例題1  sum関数をmain関数の後に記述した場合(プログラムが実行されない)。 #include <stdio.h> int main(void) { return 0; } int sum(void) { printf("%d\n",(1 + 100) * 100 / 2); return 0; } 例題2  sum関数をmain関数の先に記述した場合(プログラムが実行される)。 #include <stdio.h> int sum(void) { printf("%d\n",(1 + 100) * 100 / 2); return 0; } int main(void) { return 0; } 例題1の場合、【まずmain関数を作り、次にsum関数を作りました。この場合、main関数を解析している段階では、sum関数は発見されておらず、従って、main関数の中では、sum関数を使うことは出来なくなってしまいます。】との説明がありますが理解できません。 コンパイラがどのような順番でプログラムを処理しているか理解できていないので分からないのだと思います。 例題1の場合と例題2の場合の両方について、コンパイラがどのような順番でプログラムを処理しているのかを具体的に教えてください。 どうかよろしくお願い致します。

  • 外部シンボル "_main" は未解決です というエラーが出ます

    初めまして、プログラミング初心者です。 VC++6.0を使っています。 Win32コンソールアプリケーションで書籍に載っていたサンプルプログラムを実行したところ、 『LIBCD.lib(crt0.obj) : error LNK2001: 外部シンボル "_main" は未解決です』 『Debug/shi.exe : fatal error LNK1120: 外部参照 1 が未解決です。』 というエラーが出ます。 元々C言語のプログラムなのでmain関数が必要だということはここのログを見て分かったのですが、C++の場合はどのようにすれば良いのでしょうか? 最終的にはこのプログラムをBorland社のC++Builderで使えるようになりたいのですが… プログラムを載せたいのですが、書籍のプログラムをここに載せてもいいのでしょうか?禁止事項を読んでみたのですが、いまいちよく分からなかったので… 初歩的なところから躓いてしまい、全く進めない状況です。 大変恥ずかしいのですが、どなたかご教授願えませんでしょうか。お願いします。

専門家に質問してみよう