9

80k評判の寄稿者R..は SO で私に、関数の戻り値は定数とは見なされないため、グローバル変数を初期化することはできず、グローバル変数は定数で初期化する必要があると言いました.そして彼の言葉に忠実です.予想どおり、このプログラムの次のエラー-- プログラムは次のとおりinitializer element is not a constantです。

#include<stdio.h>
int foo();
int gvar=foo();  //ERROR

int main()
{
printf("%d",gvar);
}

int foo()
{
 return 8;
}

しかし、このコンテキストでは、上記のプログラムの次の変更されたバージョンがエラーをまったく表示せず、正常に動作する理由がわかりません。この 2 番目のプログラムでは、同じ関数の戻り値で同じグローバル変数を初期化していますfoo()。結果がこのように変動する厳密な技術的理由を教えていただけますか?宣言時に関数の戻り値を使用してグローバル変数を初期化するとエラーが発生するのに、同じ戻り値を使用した同じ初期化を内部から実行すると正常に機能するのはなぜですか?関数?

#include<stdio.h>
int foo();
int gvar;

int main()
{
gvar=foo();
printf("%d",gvar);
}

int foo()
{
return 8;
}

出力 8

4

5 に答える 5

15

その背後にある理由は、関数によって生成された値を決定するためにコードを実行する必要があり、静的およびグローバル変数を初期化するときに C で実行されるコードがないためです。

コンパイラとリンカーは連携して、グローバル メモリ セグメントのバイト イメージを準備します。コンパイラが値を提供し、リンカーが最終的なレイアウトを実行します。実行時に、セグメントのイメージは、さらに変更されることなく、そのままメモリにロードされます。これはコードが実行される前に発生するため、関数呼び出しを行うことはできません。

これは、何らかの技術的な理由でそれが不可能であることを意味するのではなく、C の設計者がそうしないことにしただけであることに注意してください。たとえば、C++ コンパイラは、グローバル オブジェクトのコンストラクターを呼び出すコード セグメントを生成します。これは、コントロールが main() に渡される前に実行されます。

于 2013-05-03T08:38:57.487 に答える
1

ケース 1 では、宣言中にグローバル変数に変数が割り当てられます。

しかし、2 番目のケースでは、foo() の戻り値でグローバル変数が割り当てられます (既に宣言されています)。

データ セクション、テキスト セクションの形成はすべてコンパイル中に発生します。

グローバル変数はデータ セクション (bss または初期化されたデータ セクション) にあるため、コンパイル時に foo() は正しく呼び出されませんか? また、コンパイル時に foo() の戻り値が不明です。

しかし、テキスト セクションが実行される 2 番目のケースでgvarは、foo() の戻り値が割り当てられます。有効です。

于 2013-05-03T08:38:04.737 に答える
0

次のように考えることができます:main()起動時に、すべてのグローバル変数はすでに初期化子の値を持っている必要があります。そして、あなたが言われたように、関数を呼び出すことによってそれらを取得することはできません。なぜならmain()、C プログラムでは実行が実際に開始されるからです。

于 2013-05-03T09:44:05.180 に答える