5

以下のプログラムは、エラーなしでコンパイルされます。

#include <stdio.h>

char addr_a[8];
char addr_b[8];

unsigned long my_addr = (unsigned long)addr_b - 8;                          // PASS
// unsigned long my_addr = (unsigned long)addr_b - (unsigned long)addr_a;   // FAIL (error: initializer element is not constant)

int main() {
        printf("%lx\n", my_addr);
        return 0;
}

興味深いことに、unsigned long my_addr = (unsigned long)addr_b - (unsigned long)addr_aコンパイラを設定すると、「エラー: 初期化要素が定数ではありません」というメッセージがスローされます。

グローバルは定数式でのみ初期化できることを知っています。また、グローバルのイニシャライザで使用できる定数式のタイプは、C 標準のセクション 6.6p7 で指定されていることも知っています。

初期化子の定数式には、より多くの自由度が許可されています。このような定数式は、次のいずれかになるか、評価されます。

  • 算術定数式、
  • null ポインター定数、
  • アドレス定数、または
  • 完全なオブジェクト型のアドレス定数プラスまたはマイナスの整数定数式。

アドレス定数から整数定数を引いたものは許可されますが、アドレス定数から別のアドレス定数を引いたものは許可されないことに注意してください。

質問:

C 標準がグローバル変数の初期化方法を制限しているのはなぜですか? C標準が受け入れるのを妨げているのは何unsigned long my_addr = (unsigned long)addr_b - (unsigned long)addr_aですか?

なぜこれが欲しいのですか?

とがそれぞれセクションの開始と終了を表しているとしaddr_aます。プログラムは、 size を持つセクションをマップしたい場合があります。trusted-firmware-aプロジェクトは、ブート ローダー ステージ 2 (BL2) でこれを行います。arm_bl2_setup.cで使用されている を参照してください。addr_b.text.text(unsigned long)addr_b - (unsigned long)addr_aBL_CODE_END - BL_CODE_BASE

4

2 に答える 2

4

静的な保存期間を持つオブジェクト(つまり、グローバル、および として定義されたローカル) は、定数式staticでのみ初期化できます。

このようなオブジェクトの初期化子で使用できる定数式の型は、C 標準のセクション 6.6p7 で指定されています。

初期化子の定数式には、より多くの自由度が許可されています。このような定数式は、次のいずれかになるか、評価されます。

  • 算術定数式、
  • null ポインター定数、
  • アドレス定数、または
  • 完全なオブジェクト型のアドレス定数プラスまたはマイナスの整数定数式。

アドレス定数と整数定数は許可されますが、アドレス定数と別のアドレス定数は許可されないことに注意してください。

アドレス定数が整数型にキャストされているため、これはまだ正確ではありません。それでは、整数定数式を定義する 6.6p6 を確認しましょう。

整数定数式は整数型を持ち、整数定数、列挙定数、文字定数、結果が整数定数である sizeof 式、_Alignof式、およびキャストの即値オペランドである浮動小数点定数であるオペランドのみを持つものとします。整数定数式のキャスト演算子はsizeof、 or演算子のオペランドの一部を除き、 算術型を整数型にのみ変換し_Alignofます。

この段落では、整数定数式の一部としてアドレス定数を整数型にキャストすることは許可されていませんが、明らかにこれは拡張機能としてサポートされているようです。

于 2021-11-24T23:32:38.757 に答える
0

C 標準が unsigned long my_addr = (unsigned long)addr_a + (unsigned long)addr_b を受け入れないようにしているのは何ですか?

根底にある理由は、「なぜ誰かがそれを望んでいるのか」です。2 つの絶対アドレスを一緒に加算しても意味がありません。結果は特定のアドレスではありません。

したがって、それは一種のニワトリと卵のようなものです。役に立たないという理由だけでなく、既存のリンカーとオブジェクト ファイル形式がそのような再配置をサポートしていないため、言語はそれをサポートしていません。たとえば、x86-64 の ELF の場合、サポートされている再配置のリストについては、psABI表 4.9 を参照してくださいS+S。また、リンカはそれをサポートしていません。これは役に立たないためであり、言語がサポートする必要がないためです。

もともと、ツールはおそらく言語の前にあったと思います (初期の C コンパイラは、アセンブリ プログラム用に設計されたリンカを使用していたでしょう)。したがって、元のツールはおそらくこれをサポートしていませんでした。言語はそうするように要求する必要がないと判断し、時間の経過とともに、どちらもそれを追加する必要性を認識しませんでした。

于 2021-11-25T02:14:14.060 に答える