C言語において
int a = 1; // 動的グローバル変数
static int b = 2; //静的グローバル変数
funcA(){
int c = 3; // 動的ローカル変数
static int d = 4; //静的グローバル変数
・
・
・
}
上記のように各種変数を初期化したとします。
"c"のような動的ローカル変数であれば、funcA()が呼ばれたときに毎回初期化されますよね?
では
・"d"のような静的ローカル変数は、初めてfuncA()が呼ばれたときに初期化されるのですか?
・"a","b"のyほうなグローバル変数は、どのタイミングで初期化されるのですか?
以上2点について伺いたいと思います。
ちなみに、組み込み機器むけのソフトウェアを想定しています。
No.13ベストアンサー
- 回答日時:
No.11 = Interest です。
> コンパイル時に"a","b","d"の領域が.dataセクションに確保される。
コンパイル時ではなく、リンク時です。リンク前は、これらのデータがどこに配置されるかまだ決まっていません。
> コンパイル時にスタートアップルーチンが自動生成され(?)
これ、違います。
スタートアップルーチンが自動生成されるとすれば、統合開発環境などを使ってプロジェクトを生成したときです。統合開発環境を使ってなければ、スタートアップルーチンを手で書くこともあります。(どこかからコピーしてくるほうが楽ですが。)コンパイル時に自動生成されるものではありません。
> main関数実行前に、
これは間違いではありませんが、注意が必要です。
CPUに電源が供給されて一番最初に走り始めるプログラムがスタートアップルーチンです。スタートアップルーチンが「いわゆるmain関数」を呼び出します。すでにご存じと思いますが、組み込みの世界では必ずしも main関数があるわけではないので、「main関数実行前に」という考えかたは適切ではありません。
> スタートアップルーチンが変数をROM→RAMへとコピーする際に、.dataセクションの変数を初期化する。(.bssセクションは0初期化する)
「変数をROM→RAMへとコピーする」ことと、「.dataセクションの変数を初期化する」ことは同じことです。言い換えれば「.dataセクションの変数を初期化するために、ROMに格納されている初期値をRAMへとコピーする」ってこと。
この回答への補足
返事が滞っており申し訳ありません。
非常にわかりやすく説明いただきありがとうございます。
処理の流れは理解できたのですが
>言い換えれば「.dataセクションの変数を初期化するために、ROMに格納されている初期値をRAMへとコピーする」ってこと。
リンク時にデータ領域の確保とともに初期化していまえば
わざわざスタートアップ時に初期化する必要がなく
起動時間の短縮につながるのでは?と思いました。
度々申し訳ございませんが
よろしくお願いいたします。
No.15
- 回答日時:
#2です。
C言語の質問への回答としては、書いたとおり、「mainの実行直前」で、それ以上区分けは出来ません。
補足での質問はすでに、C言語の枠を越えてOSの範囲に入ってきています。
これ以上の質問は、OSを限定してCコンパイラも限定して~例えばWindowsのVisual C++とか、Linux-Fedoraのgccとか~別途適当なカテゴリで質問し直すべきでしょう。組み込みの環境でもいろいろOSがありますし、OSの無い環境もありますし。
No.14
- 回答日時:
No.11 = No.13 = Interest です。
> リンク時にデータ領域の確保とともに初期化していまえば
> わざわざスタートアップ時に初期化する必要がなく
> 起動時間の短縮につながるのでは?と思いました。
ご存じのとおり、「リンク」は、ビルド(コンパイル -> リンク)の流れで、普通はPC上の開発環境で実行します。このときはまだビルドしてできたプログラム(hoge.motとか、hoge.sとか hoge.hex とか)がターゲットとなるCPUのROMに書き込まれていませんよね。
できたプログラムをターゲットCPUをbootモードなどに設定してROMに書き込んで、そのターゲットCPUをuserモードに戻してから再起動して、初めてプログラムが動き始めます。
CPUに内蔵されているRAMを使う場合はバスの設定が不要ですが、外部RAMを使用する場合はCPUが起動してからバスの設定が必要です。バスの設定が終わって初めてその外部RAMにアクセスできるわけですから、当然、バス設定前の外部RAMにはアクセスできませんし、外部RAMの初期化もできません。
もっといえば、CPUに電源が入ってないとRAMの値は保持されないわけで。
「リンク時にRAMを初期化」というのが変なことを言っているのが分かっていただけましたでしょうか?
No.12
- 回答日時:
a,b,d については main() が呼ばれる前に初期化されます。
組み込みシステムといっても最近は規模が大きいものもあってパソコンと変わりの無いものもありますがそうでないものということで話します。
初期値付きの変数の初期値はROMに格納されています。
その初期値はmain関数を呼ぶ前にスタートアップルーチンによりRAMにコピーされるのです。
初期値のない変数はスタートアップルーチンによってゼロクリアされます。
スタックやヒープはクリアされないのが普通ですが初期化する場合もあります。
組み込みシステムのROMにはオブジェクトコードと初期値付き変数の初期値が格納されています。
システムによっては、オブジェクトコードをROM上で実行するシステムとRAM上にコピーして実行するシステムがあります。
RAMがコストアップの要因になるシステムではROM上で実行します。
ROMでは実行速度が問題になる場合はすべてをRAMにコピーしてから実行します。一部だけRAMというのもあります。
前者の場合、スタートアップルーチンが変数の初期値をRAMにコピーし、初期値なしの変数をクリアした後にmain関数を実行します。
後者の場合は、スタートアップルーチンがコードと初期値をRAM上にコピーし、初期値なしの変数をクリアした後にmain関数を実行します。
コンパイラはROM上のどの部分をRAM上のどこにコピーすればいいかという情報を作成しますのでスタートアップルーチンはそれを利用してコピーするようにします。
メーカーの開発環境ではこの部分は自動的に生成してくれますので気にする必要は無いのですがそのような環境が無い場合、あるいはカスタマイズする必要がある場合などは自前で用意する必要があります。
この回答への補足
>みなさま
かなり詳しいご説明ありがとうございます。
いろいろなご意見があるようで、正直混乱しております。
現在のわたしは
・コンパイル時に"a","b","d"の領域が.dataセクションに確保される。
・コンパイル時にスタートアップルーチンが自動生成され(?)、main関数実行前に、そのスタートアップルーチンが変数をROM→RAMへとコピーする際に、.dataセクションの変数を初期化する。(.bssセクションは0初期化する)
という理解なのですが、これで正しいのでしょうか?
No.11
- 回答日時:
cygwinはコンパイラじゃないっす。
cygwin使ってるならGCCでは?CPUが立ち上がった直後の世界なので、OSも関係なし。
ルネサステクノロジのSH2で、グローバル変数が初期化されるところの具体例出します。コンパイラはKPIT GCCです。
--- 以下、start.asm から抜粋 ---
!load data section from ROM to RAM only if ROMSTART is defined
#if ROMSTART
! initialise sections
mov.ledata,r1! edata in r1
mov.lmdata,r2! mdata in r2
mov.ldata,r0 ! data in r0
cmp/eq r0,r1
btstart_1
nop
start_l:
mov.b @r2,r3 !get from src
mov.b r3,@r0 !place in dest
add #1,r2 !inc src
add #1,r0 !inc dest
cmp/eq r0,r1 !dest == edata?
bfstart_l
nop
start_1:
#endif // ROMSTART
--- 抜粋ここまで ---
startup.asm は、ごらんのとおりアセンブリ言語で書かれたスタートアップルーチンです。ご質問の外部変数の初期化は、スタートアップルーチンの中で行っています。上記のアセンブリコードでは、 ROM上のmdataセクションに外部変数の初期値が入っており、これをRAM上のdataセクションにコピーしています。bss(初期値なし)セクションのゼロクリアは上記アセンブリコードより後で行っています。
参考:
http://mobile-robots.way-nifty.com/daily_report/ …
No.10
- 回答日時:
a, b, dのメモリ領域はコンパイル時に割付けられます。
より厳密に言えば、具体的なアドレスが決定するのはリンク時です。静的記憶域期間を持つ初期値付きオブジェクトは、一般的には、.dataセクションに配置され、スタートアップでROM→RAMに転送されます。ただし、今回の場合は、.textセクションのプログラムと一緒にブート時に転送されることになると思います。
ゼロクリアされるのは.bssセクション(つまり初期値無しオブジェクト)だけです。
dに関しての誤解は、C++における定数式以外の初期化子との混同ではないかと思います。例えば、
void func()
{
double y = std::sqrt(3.0);
...
}
のyは、funcが呼び出され、最初にyの宣言位置に実行パスが差し掛かったときに初期化されます。それ以前はゼロクリアされることになります。
No.9
- 回答日時:
★アドバイス
>1."a","b","d"ともコンパイル時にメモリに領域が確保されると同時に初期化される。
コンパイル時ではありません。
実行されたときに初期化されます。
>2."a","b","d"ともスタートアップルーチン時にメモリに領域が確保されると同時に初期化される。
これです。
BSSセクションをすべてゼロで初期化。
その後に指定された『値』1とか2などで初期化。
この順です。
>3."a","b"はスタートアップルーチン時、"d"は該当関数が呼ばれた時にメモリに領域が確保されると同時に初期化される。
これは間違いです。
No.8
- 回答日時:
a, b, dはいずれも静的記憶域期間を持ちます。
初期化は通常スタートアップで行います。ちなみに、aは外部結合、bは内部結合、dは無結合になります。
cは自動記憶域期間を持ちますので、funcAが呼び出され、その宣言部分に実行パスが差し掛かるたびに初期化されます。
これに関しては、組込みであろうがなかろうが関係ありません。ただし、main関数云々の話はフリースタンディング環境では通用しません。
この回答への補足
>みなさま
丁寧なご回答ありがとうございます。
"c"の自動ローカル変数に関しては、関数呼び出し時に初期化でOKのようですが
"a","b","d"に関しては意見が分かれるようですね。
まとめると
1."a","b","d"ともコンパイル時にメモリに領域が確保されると同時に初期化される。
2."a","b","d"ともスタートアップルーチン時にメモリに領域が確保されると同時に初期化される。
3."a","b"はスタートアップルーチン時、"d"は該当関数が呼ばれた時にメモリに領域が確保されると同時に初期化される。
の3種類の意見に分類できそうですが、これは環境によって初期化の方法が違うのでしょうか?
私の場合は、Winマシンでcygwinというコンパイラでコンパイルし
組み込み機器のROMにファームを焼き
機器の電源ONと同時にブートローダによってファームをROMからRAMに移す
といった処理をしています。
ちなみに機器のOSはLinuxです。
No.7
- 回答日時:
★アドバイス
組み込み系は詳しくありませんので一般論で回答しておきます。注意。
・次のリンクの
『セクションとか.textとか』
『初期化してない変数とか.bssセクションとか 』
を読んでみて下さい。
http://www.ertl.jp/~takayuki/readings/info/→『「infoを読め」と言われたら...』
さらに詳しく知りたい場合は『BSS セクション』で検索してみましょう。
>"c"のような動的ローカル変数であれば、funcA()が呼ばれたときに毎回初期化されますよね?
↑
自動変数だね。
毎回初期化されます。
>"d"のような静的ローカル変数は、初めてfuncA()が呼ばれたときに初期化されるのですか?
↑
これは『a』『b』と同じくスタートアップ・ルーチンで初期化されます。
スタートアップ・ルーチンはmain()関数が呼ばれる前の処理です。
プログラムが起動した最初の1回しか初期化されません。
>"a","b"のyほうなグローバル変数は、どのタイミングで初期化されるのですか?
↑
これも『d』と同様にスタートアップ・ルーチンで初期化されます。
・最後にもう一つ次のリンクを読んでみて下さい。
http://www.ertl.jp/~takayuki/readings/c/no10.html→『初めてのC言語 - 第10回 三度目のスタートアップ』
No.6
- 回答日時:
組み込み向けですよね。
どのコンパイラか分からないので一般論ですが、通常はデータセクションに最初から埋め込まれています。
データセクションはROM領域に乗るのが普通なので、何らかの方法でRAMにコピーして使います。大抵はブートコードでコピーするはずです。
どのタイミングといわれれば、コンパイル時かブート時ということでいいんじゃないでしょうか。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
- その他(プログラミング・Web制作) pythonのグローバル変数 2 2022/11/25 18:02
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# 競技プログラミングに関する質問です。 3 2022/04/03 19:51
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語をコンパイルするとコンピ...
-
<unistd.h>をVisualStudioでつ...
-
実行後にコンパイルに失敗しま...
-
アプリケーションのDLLファイル...
-
math.hに含まれる関数が使えない
-
ビープ音が鳴りません・・・
-
c言語です コンパイルした時に...
-
再起動しないとADOが使えなくな...
-
VS2010環境で2点ほど質問
-
<math.h>ヘッダを入力している...
-
'hcw'がみつかりません
-
すべてのリビルド: 0 正常、 0 ...
-
VCでコンパイラ実行時に警告を...
-
</body>の直上にJavaScriptを入...
-
C言語で作ったらWindowsでもMac...
-
C言語で、配列を使ったsinカー...
-
Linux(g++)とAIX(XL C++)の挙動...
-
64bit環境で32bitでコンパイル...
-
VC++6.0の混在モード
-
CLRアプリと通常のアプリとの違い
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
<unistd.h>をVisualStudioでつ...
-
アプリケーションのDLLファイル...
-
共有ライブラリの内容確認について
-
シリアル通信の受信待ちについて
-
C#で char型とstring型の比較で...
-
64ビットのlinuxで32ビットメモ...
-
Verilog_HDLでのdefineとifdef
-
math.hに含まれる関数が使えない
-
自作DLLの中身を暗号化
-
C言語で作ったらWindowsでもMac...
-
実行後にコンパイルに失敗しま...
-
lhafileをインストールしたい
-
c言語です コンパイルした時に...
-
ビープ音が鳴りません・・・
-
すべてのリビルド: 0 正常、 0 ...
-
gcc バージョン違いによるコン...
-
Cのコンパイルでコメントアウト...
-
CLRアプリと通常のアプリとの違い
-
「インクルードファイル 'pthre...
-
MVSマシンで0C7でABENDしたので...
おすすめ情報