8

Is it possible in C to have mutually referencing static variable initializers, as shown in the example below?

The example compiles, without warning in gcc -Wall, if line 2 is added to pre-declare "B". Line 2 is distasteful because it also defines B, as does line 4. The splint lint program, with -weak checking, warns that "B" is defined twice: "Variable B redefined. A function or variable is redefined. One of the declarations should use extern."

Typically a declaration would be made with the extern keyword, but extern and static cannot be used together, and will not compile under gcc.

#include <stdio.h>                               /*1*/
volatile static void * B;                        /*2*/
volatile static void * A = &B;                   /*3*/
volatile static void * B = &A;                   /*4*/
int main()                                       /*5*/
{                                                /*6*/
    printf("A = %x, B = %x\n", (int)A, (int)B);  /*7*/
    return 0;                                    /*8*/
}                                                /*9*/

Thank you

4

3 に答える 3

5

volatilewith との関係での奇妙な配置にもかかわらず、投稿したコードは完全に有効な C です。これは、暫定定義staticと呼ばれる C 固有の機能を使用しています。この機能により、プログラム内に 1 つだけが存在することが保証されます。つまり、 の両方の定義が同じエンティティを定義します。「不味い」ということはありません。BB

スプリントから得られる警告は無効です。C++ 言語では、これは確かに複数定義エラーを構成しますが、C ではそうではありません。C 言語のコンテキスト内でのコメントexternはまったく意味がありません。

于 2012-10-02T21:42:45.523 に答える
3

これは無意味です。

編集:

&Bはい、「extern」には必要ありvoid**ません (AndreyT と Adam Rosenfield に感謝します) void*

もちろん、 にvoid**キャストしvoid*ますが、ポイントは何ですか? 相互にエイリアスまたはポインターが必要な場合は、3 番目の変数 "バッファー" を宣言し、A と B でそれを指すだけです。

unsigned char SomeBuffer[LENGTH];

void* A = SomeBuffer;
void* B = SomeBuffer;
于 2012-10-02T21:38:10.890 に答える
0

循環ループを定義しているように見えるかもしれませんが、実際にはそうではありません。C&演算子はアドレス取得演算子であり、問​​題の変数のアドレスを取得します。

@AndreyT が指摘したように、2 行目は暫定的に定義する B効果があるため、3 行目はそれを認識します。2 行目でメモリの場所を割り当て、4 行目でそこに値を入れると考えることができます。B

このコードは、次のように記述した場合と機能的に同じです。

volatile static void * A;
volatile static void * B;
int main()
{
    A = &B;
    B = &A;
    printf("A = %x, B = %x\n", (int)A, (int)B);
    return 0;
}                    

したがって、3 行目でAのアドレスを指すように定義しますBB4 行目では、 のアドレスを指すように定義しますA

Aそれを言っBて、次のメモリアドレスを持っているとしましょう:

&A == 0xAAAAAAAA
&B == 0xBBBBBBBB

3 行目のコードは次のことを行います。

A = 0xBBBBBBBB;

次に、4 行目で次の処理を行います。

B = 0xAAAAAAAA;

逆参照するAB、次のようになります (注意、最初に逆参照可能なポインター型にキャストする必要があります)。

*A --> 0xAAAAAAAA
*B --> 0xBBBBBBBB

これは完全に有効ですが、コードで意図していることではない可能性があります。

2 つの異なる値が作用していることに注意してください。最初はポインタの値です。2 番目はポインタのアドレスです。

使用する必要がある唯一の理由はextern、別のオブジェクト ファイルで定義された変数を使用することです (つまり、 でfile1.c定義されたグローバル変数を使用したい場合file2.c)。グローバル変数に適用されるstaticキーワードは、変数がファイル静的であるか、そのファイル内でのみ使用できることを意味します。したがって、両者は明らかに対立しています。

于 2012-10-02T23:41:10.663 に答える