3

staticあるファイルで定義されている関数.cは、他のファイルからはアクセスできないと言われました。しかし、次のプログラムでは、static void show()別のファイルから関数にアクセスできます。staticCの関数についての私の理解は間違っていますか?

ああ(最初のファイル):

static void show()
{
printf("I am in static show function in a.c");
}

bc(別のファイル):

#include"a.h"
void main()
{
show();
}
4

3 に答える 3

11

#include含まれているファイルの内容をコピーして貼り付けることで機能することを忘れないでください。したがって、あなたの例では、#includeが処理された後、次のようになります。

static void show()
{
printf("I am in static show function in a.c");
}

void main()
{
show();
}

だからはっきりとmain見ることができますshow1

解決策は、.cファイルを使用しないことです。 一般に、ヘッダー(.h)ファイル#includeのみを使用する必要があります。#include静的関数はヘッダーファイルで宣言または定義しないでください。そのため、静的関数mainを表示することはできません。


1.ただし、実際には、関数の2つの定義があります。1つはinで、もう1つはinです。関数の場合、これは問題ではありませんが、関数以外の場合はリンカーエラーが発生します。showa.cb.cstaticstatic

于 2012-06-17T17:36:51.793 に答える
6

staticキーワードは、リンケージ仕様をInternalLinkageに変更します。
としてマークされた関数は、その変換ユニット(TU)staticでのみ表示されます。

おそらく、関数にアクセスする特定のTUで同じ名前のシンボルを使用できます。あなたが私たちにコードを見せた後にのみ、それのどの部分に答えることができるか。

編集:
ヘッダーファイルで関数 を定義するstaticと、同じ関数のコピーが、それをインクルードするすべての変換ユニットで作成されます。そのような関数の各インスタンスは、個別の関数(各関数のアドレスは異なります)として扱われ、これらの関数のインスタンスには、staticローカル変数と文字列リテラルの独自のコピーがあります。

明らかに、これは機能しますが、生成されたバイナリのサイズが大きくなる可能性があります。

于 2012-06-17T17:24:05.990 に答える
1

他の答えは正しいですが、静的関数が別のファイルからアクセスできないと言うのは正確ではありません。関数ポインタを介して関数にアクセスすることが可能です。関数の名前は、別の翻訳単位ではアクセスできないと言った方が正確です。

Cソースコードを実行可能プログラムに変換することは、次のような概念的な段階で構成されていることに注意してください。

  1. 前処理(#includeディレクティブがインクルードされたファイルの内容に置き換えられる)
  2. コンパイル(一度に1つの翻訳単位を処理します)
  3. リンク(翻訳ユニットが最終的なプログラムにまとめられる)

3つのファイルがあるとします。 foo.h

typedef void (*void_function_p)(void);

extern void_function_p foo(void);

foo.c

#include "foo.h"
#include <stdio.h>

static void baz(void) {
    printf("worked!\n");
}

void_function_p foo(void) {
    return baz;
}

bar.c

#include "foo.h"
#include <stdio.h>

int main(void) {
    (*foo())();
    return 0;
}

このプログラムは、「動作しました」をコンパイルして出力します。それが実行されるとき。

ここには2つの翻訳ユニットがあります。1つは、前処理されたコードですfoo.c(これは、動作方法のために、および#includeのコードも含まれます)。もう1つは、前処理されたコードです(これも、とにコードの独自のコピーがあります)。foo.hstdio.hbar.cfoo.hstdio.h

関数fooに静的関数へのポインタを返すようにすることで、関数bazから呼び出すことができます。bazmain

ここで、次のように変更するとどうなるかを考えてmainみましょう。

int main(void) {
    (*foo())();
    baz();
    return 0;
}

bazこのコードは、この翻訳ユニットの名前を他の翻訳ユニットの定義にリンクできないため、リンカーエラーが発生しますbaz

これが静的関数の最初の利点です。別のプログラマーがbaz別の変換ユニットから誤って関数にアクセスすることはありません。

ここで、次のように変更するとどうなるかを考えてbar.cみましょう。

#include "foo.h"
#include <stdio.h>

static void baz(void) {
        printf("still works!");
}

int main() {
        (*foo())();
        baz();
        return 0;
}

このコードはコンパイルされ、「動作しました」と出力されます。続いて「まだ動作します!」

これは、静的関数の2番目の利点です。同じ名前の2つの関数を(異なる変換単位で)定義しました。

両方の静的定義を同じ変換単位に入れようとすると、baz2回定義することについてコンパイラエラーが発生します。

最後に、プログラムを現在の状態のままにしてすべてのを削除すると、(外部リンケージを使用して)2回定義されているstaticため、リンカーエラーが発生します。これは許可されていません。baz

于 2013-01-15T18:24:57.803 に答える