web-dev-qa-db-ja.com

静的インラインボイドとボイドの違いは何ですか?

私はC言語で作業していて、以前に誰かが書いたコードを変更しています。私はいくつかのことに苦労していて、何が起こっているのかをできるだけ理解しようとしています。それで、私の質問が述べたように、関数を作成するときのstatic inline voidvoidの違いは何ですか?長い投稿を前もってお詫びしますが、私が調査を行ったことを知ってもらいたいのですが、私が見つけたものがわかりません。

私は見つけました staticの説明 それは私を混乱させます:

静的指定子は、関数を他のファイルから参照できないことを示します。つまり、名前はリンカによってエクスポートされません。

これを読んで、関数を参照することは関数を呼び出すこととは異なると思いますか?この関数は別の.cファイルから呼び出されるためだと思います。その場合、関数を参照しているのは何ですか?

同じウェブサイトを通して、彼らは インライン関数 を説明します、そして私はそれが何を意味するのか理解していません。

__inlineキーワードは、関数呼び出しのすべてのインスタンスの関数定義内のコードを置き換えるようにコンパイラーに指示します。ただし、置換はコンパイラーの裁量でのみ発生します。たとえば、コンパイラは、アドレスが取得された場合、または関数が大きすぎてインライン化できない場合、関数をインライン化しません。

え?

どんな助けでも大歓迎です、そして私はもう一度ひどく長いポストをお詫びします。

以下はfile1.cにあります(重要ではないと思うので一般名を使用します)

COMPLEX cNoiseSample;
CGauss( &cNoiseSample, loopbackRadio->pState );

以下はfile2.cにあります

static inline void CGauss( COMPLEX * pcGauss, P_OS_UNIFORM_Rand_STATE pState )
{
    //code
}
16
TZPike05

staticは、別のコンパイルユニット(ソースファイル)から参照できないことを意味します。 「参照される」とは、呼ばれる、または名前で参照されることを意味します。関数ポインタに割り当てられています。

inlineは、関数のコードを、分岐先の個別の関数として生成するのではなく、呼び出された場所でインラインで生成する必要があるというコンパイラーへのヒントです。これは通常、パフォーマンス上の理由から行われます。 Microsoftの引用に対処するには:

アドレスが取得された場合、または関数が大きすぎてインライン化できない場合、コンパイラーは関数をインライン化しません。

インライン関数は、別個のエンティティとして存在しないため、アドレスがありません。そのコードは、呼び出し元のコードとシームレスに絡み合っています。したがって、関数のアドレスを取得する場合(たとえば、ポインターに割り当てる場合)、コンパイラーはそれを実際の関数として生成する必要があり、インライン化することはできません。

voidは、関数が値を返さないことを意味します。


コードサンプルを見ると、どこかにCGauss()の別の定義があり、これはfile1.cから呼び出されているのに対し、file2。 cは独自のプライベートバージョンを呼び出しています。それ、またはfile1.c#includeing file2.c。それは厄介でしょう。

13
Graham Borland

staticは、複数のソースファイルがある場合にのみ意味を持ちます。 static関数または変数に別のファイルの関数からアクセスできないことを指定します。

inlineは、特定の場合にコードを高速化するコンパイラー最適化です。関数を呼び出すときはいつでも、それに関連するオーバーヘッドがあります。したがって、コンパイラーができることは、インライン化されたコードを(ほぼ)コピーして貼り付けて、関数をすべて取り除くことです。

インライン化の例を次に示します。

int dotproduct(int x1, int y1, int x2, int y2) {
    return multiply(x1,x2)+multiply(y1,y2);
}

inline int multiply(int a, int b) {
    return a*b;
}

コンパイラはこれを次のように変換します。

int dotproduct(int x1, int y1, int x2, int y2) {
    return x1*x2+y1*y2;
}

派手になりたい場合は、内積関数をインライン化することもできます;)

inlineキーワードは、特定の関数をインライン化するためのコンパイラーへの単なるナッジであることに注意してください。それはそれ自身の判断に応じて実際にそれをするかもしれないし、しないかもしれません。

7
tskuzzy

静的キーワード

C関数の静的定義とは、(ドキュメントに記載されているように)この関数は定義されているソースファイルからのみアクセスできることを意味します。この意味での「参照」という用語は、この関数を呼び出すか、たとえば関数ポインターを取得することを意味します。 。

インライン化

通常、Cで関数を作成すると、コンパイラーはこの関数のマシンコードを生成します。

foo:
   /* some machine code */
   ret

この関数を呼び出すたびに、コンパイラは次のような命令を挿入します

  call <foo>

これは、「fooにジャンプし、そこで見つけたものを実行し、ret命令に遭遇したら、この場所に戻る」ことを意味します。

対照的に、インライン関数の場合、コンパイラーは個別の関数foo()を生成しませんが、代わりに関数fooのマシンコードをすべての呼び出しサイトに挿入します。このコードを実行すると、同じ効果があります。

では、なぜそれを行うのでしょうか。コードをインライン化すると、2つのジャンプ(呼び出しとそれぞれのret)を節約できるという利点があり、コードの実行が少し速くなります。欠点として、呼び出し可能な関数のコピーを1つだけ持つのではなく、すべての呼び出しサイトにマシンコードを挿入するため、コードが大きくなります。そのため、通常は小さな関数のみをインライン化します。

また、インライン関数への関数ポインタを取得できず、インライン関数にブレークポイントを簡単に設定できないため、デバッグが困難になります。

したがって、インライン化は最適化オプションとしてコンパイラーに残され、C++のインライン、インラインディレクティブ、またはGCCの__attribute((inline))などのキーワードを使用することにより、コンパイラーに次のようなヒントを与えるだけです。インライン化はここで試す価値があるかもしれません。

2
BjoernD

staticは、基本的に、関数が定義されているソースファイルの外部で「非表示」になっていることを意味します。

インラインで、基本的に関数呼び出しコードをソースに直接コンパイルするようにコンパイラーに要求します(関数呼び出しが関数のコードで置き換えられるように)コンパイル時に関数が呼び出されるそれぞれの場所で-ただし、必ず発生するわけではありません。それはあなたのコンパイラにそれを提案するだけです。

それはそれよりも技術的であり、あなたははるかに良い答えを得る可能性がありますが、単純な言葉でこれは用語が意味するものです。

0

上記のすべてを追加したいと思います。上記を読む前に、Cプログラミングの仕組みを理解することが重要です。単純にオープンコードを書く場合

Setup(){
    int MainVar
}

MyRoutine(){
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

そうすれば、誰でも2番目のプログラムから直接MyRoutine.myVar1にアクセスできます。 MyRoutineで使用する前に、myVar2の値を変更できます(1.保護されていない場合、2。そこにあることを知っている場合、3。機能を知っている場合)。元のプログラマーが意図した。

銀行のプログラムを作成していて、コードを脆弱なままにして、ルーチンで他の銀行のWITHDRAWLを変更せずにDEPOSITの値を変更できると想像してください。他の誰かがやって来て、その値を2または10ずつ変更する別のプログラムを作成し、存在しない場所でお金を稼ぐことができます。ただし、コード、ルーチン、メソッド、または変数の前にSTATICを付けると、これらの項目にアクセスしたり、表示したり、他のプログラムで変更したりすることはできません。

静的はいつでも使用でき、ルーチン全体を閉じたり、個々の変数を閉じたりすることができます。したがって、他の人がコードの特定の側面に変更を加えることを許可しますが、保護する必要のある側面は保持します。

MyRoutineにStaticを設定すると、誰かが別のプログラムからMyRoutineを実行できなくなります。 MyVarsはMyRoutine内で宣言されているため、別のプログラムからアクセスできません。ただし、プログラム内の他の場所で宣言されたMainVarという変数がある場合は、アクセス可能です。

Setup(){
    int MainVar  // This can be accessed from outside this code
}

static MyRoutine(){  // Because of static these vars are not
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

そしてここでは、静的な変数のみが保護されます。 myVar3は他の場所から読み取ることができ、交換が完了したことを別のルーチンに通知します。

Setup(){
    int MainVar    // This can be accessed from outside this code
}

MyRoutine(){
   static int myVar1;  // This can NOT be accessed from outside this code
   static int myVar2;  // This can NOT be accessed from outside this code
   bool myVar3;        // This can be accessed from outside this code
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}
0
KeyWizard