Cの静的関数とは何ですか?

ベストアンサー

ファイルで定義された関数は、別のファイルでアクセスできることがわかっています。関数を別のファイルで呼び出さないように制限したい場合は、静的にすることができます。

したがって、静的関数は呼び出し可能な関数です。それらが定義するのと同じファイル内に

次の構文を使用して静的関数を定義できます

static return\_type function\_name(arguments)

{

function\_body;

}

指定された数値の平方根を見つける関数です

static long int getSquare(int num){

return (num*num);

}

C言語での静的関数の例を示すプログラム

#include

//static function definition

static long int getSquare(int num){

return (num*num);

}

int main()

{

int num;

printf("Enter an integer number: ");

scanf("\%d",&num);

printf("Square of \%d is \%ld.\n",num,getSquare(num));

return 0;

}

出力

Enter an integer number: 36

Square of 36 is 1296.

静的関数が必要な理由

関数はコードを再利用するために使用されるため (すなわち、 作成したコードは、関数に配置することで別のファイルにアクセスできます)が、別のファイルで共有(呼び出し可能)してはならない関数

静的関数は、宣言の競合の問題を処理するのにも役立ちます。 -同じ名前の2つの異なるファイルに2つの関数がある場合、関数宣言は競合します。それらを静的にすることができます。

このような要件を満たすために、静的にすることができます。

回答

簡単な回答:これは、関数名が現在コンパイルされているファイルでのみ表示および呼び出し可能であることを意味します。個別にコンパイルされた他のファイルは、関数名を認識しないか、呼び出すことができません。その後、それらは同じ名前の独自の静的関数を持つ可能性があります。これにより、ファイルのインクルード、およびオブジェクトファイルとバイナリライブラリのリンクでの名前の衝突が回避されます。

Cのストレージには4つの異なるストレージクラスがあります。

  • auto (自動)これは「通常」(デフォルト)で、キーワード auto を使用しますが、デフォルトであるため、通常は指定されません
  • レジスタは、作成されたコードを最適化して格納するためのコンパイラへの「ヒント」です。処理を高速化するためのCPUレジスタの値。コンパイラはそれができるかどうかを試みますが、そうでない場合は通常と同じです。
  • extern externalは、あることを意味します。その名前のグローバル変数は1つだけであり、それをexternとして宣言するすべてのファイルがそのストレージを使用します。 1つのファイルは、それを通常の変数としてグローバルに宣言し、コンパイル時に割り当てられます。
  • 静的 Cソースファイルのストレージ指定子は、いくつかの異なるもの。
  1. 名前とストレージは、同時にコンパイルされている他のファイルにエクスポートされません。これにより、各ファイルに衝突しない同一の名前を付けることができます。
  2. 変数用に作成されたストレージは静的ストレージ領域に作成され、プログラムの開始時に0に初期化されるか、明示的な値で初期化されます。
  3. 静的変数の初期化は一度だけ実行されます。 (コンパイル時)。その後、割り当てられた値は、プログラムの存続期間中、または割り当てによって変更されるまで保持されます。
  4. 関数内で宣言された静的ストレージには関数スコープがありますが、静的割り当てです。これは、ストレージがプログラムの存続期間中永続的であり、関数スタックフレームが関数呼び出しに割り当てられたときに作成されないことを意味します。複数の関数呼び出しを通じてその値を保持します。コードのブロックが戻った後にスタックから回復されても、ストレージは存続します。

int accumulate( unsigned int x)

{

static unsigned int acc = 0;

acc = acc + x;

return acc;

}

  1. 上記はvar accは各呼び出しを通じて値を保持するため、入力の実行中の集計。 accは、プログラムのロード時に0に初期化されます。
  2. 静的変数のRAMにはアドレスがあり、参照または値によって関数に送信できます。
  3. スコープ外の静的変数と同じ名前の小さなスコープ(関数内で定義)の変数は、他の変数と同じように静的変数をシャドウします。
  4. 静的変数はそうではない場合があります。外部ファイルにエクスポートされるため、値によってパラメーターとして明示的に送信されない場合、コンパイルドメイン間で値が失われる可能性があります。 (落とし穴!)
  5. 4と同様に、他のファイルは、 extern として静的変数にアクセスできません。 自動(通常)変数。動作せず、バグのあるプログラムがクラッシュし、コンパイラがだまされて見落とされる可能性があります。
  6. 静的変数は宣言時に初期化される場合がありますが、初期化値は評価可能な定数式である必要があります。コンパイル時ではなく、コンパイル時に計算できない値ではありません。静的変数を、パラメーター変数などの不明な値、またはコンパイル時に発生しなかった関数呼び出しの結果で初期化することはできません。

int accumulate( unsigned int x)

{

/* ERROR x is not a compile-time constant. */

static unsigned int acc = x;

static unsigned int acc = 0; /* OK */

acc = acc + x;

return acc;

}

静的関数

  1. Cの静的関数にはファイルスコープがあります 静的関数は同じ翻訳単位内の別のファイルによって呼び出されます。翻訳ユニットは、一度にコンパイルされる前処理の後にコンパイラに入るすべてのソースコードです。静的関数は、静的変数にアクセスしたり、他のファイルから静的関数を呼び出したりすることはできません。したがって、関数へのアクセスを現在のファイルに制限する場合は、静的にすることができます。そのファイルにはその名前の関数が1つしか存在できないため(通常の関数にも当てはまります)、多くの場合、ユーティリティ関数はヘッダーファイルに入れられ、複数のコンパイルに含まれます。ヘッダーはプリプロセッサコマンドで保護されます。コンパイルユニットに複数回含まれている。すべての標準Cライブラリヘッダーはグローバル関数でいっぱいであり、それらはコンパイル時に1回だけコンパイルされるように保護されており、グローバル関数です。静的関数はありません。静的関数は「内部リンケージ」を持っていると言われています。つまり、同じ最終プログラムまたはライブラリにリンクされていても、他のコンパイル済みモジュールでは表示されません。関数が static でない場合、Cではその関数はグローバル関数であり、プログラム全体でグローバルに使用できます。つまり、プログラム全体で print という関数を1つだけ持つことができます。これを回避するには、関数と変数を静的にします。そうすれば、名前が衝突することはありません。
  2. 関数はグローバルであり、デフォルトでextern ですが、定義されているファイルを除きます。したがって、 extern は、Cソースで関数とともに使用されます。これは、すでに暗黙的に存在しているためです。これが、変換ユニット内の任意のファイルから通常の関数を呼び出すことができる理由です。 「外部リンケージ」があると言われています。つまり、リンクされると、モジュール内の任意のファイル、またはリンクされたプログラム内の他のモジュールから表示および呼び出し可能になります。
  3. 関数プロトタイプ宣言は「暫定的な定義」であり、暗黙的に外部になります。プロトタイプ宣言が初めてスキャンされた後のコードは、完全な定義が最終コードに存在する限り、関数を呼び出すことができます。つまり、「実際の定義」が実際に存在する必要があります。そうでない場合、リンクフェーズは失敗します。これが、Cのヘッダーに通常、関数のソースコードが含まれておらず、コンパイルする必要はないが、リンク段階にある理由です。
  4. 静的関数プロトタイプ宣言は「暫定的な定義」であり、明示的に外部ではありません。完全な定義が現在の翻訳単位(同時にコンパイルされる)に存在する必要があります。存在しない場合、コンパイルは失敗します。最新のCコンパイラは、実際の関数呼び出しよりも早く発生する限り、定義からプロトタイプを合成します。いわゆる「前方宣言」により、後で実際の定義とともに暫定的な定義を使用でき、データ構造やライブラリの編成でさまざまな用途があります。
  5. ファイル署名の最初の定義は、静的または外部を含むプログラム全体に使用される定義です。関数が最初に定義されると、最初に静的として宣言された場合、後でstaticキーワードなしで再定義されたとしても、常に静的になります。最初にextern(デフォルト)として宣言されている場合、静的として再定義することはできません。

static void f(int); /* Function is always static */

...

void f(int x) { ….} /* static , not exported, no error */

void f(int); /* Function is always global */

...

static void f(int x) { ….} /*ERROR NOT STATIC */

clang: "error: static declaration of "f" follows non-static declaration"

  1. ブロックスコープで定義された関数は静的として宣言できません。 ブロックの外部で作成できるのはファイルスコープの静的関数定義のみです。ファイルスコープをファイル全体より小さくすることはできないため、これはロジックの観点からは理にかなっています。したがって、静的関数、または少なくともプロトタイプをファイルの非常に早い段階で定義します。
  2. 静的戻り値の型ではなく、関数を参照します 。必要に応じて、戻り値の型の後にstaticキーワードを配置できますが、そうすると奇妙になり、人々を混乱させることになります。戻り値は静的ではなく、関数は静的です。
  3. 静的関数定義は同じファイルまたはインクルードファイルでその前に定義されたグローバルなもの。 その名前で定義された関数がすでに存在する場合、静的関数や同じ名前の関数で再定義することはできません。

Cは、C ++のように関数と変数の名前を内部的に変更しないため、関数のオーバーロードをサポートしていません。 C ++は、クラスの一部であるかどうかやそのパラメーターが何であるかなど、いくつかの追加の種類のデータを示すコードネームで関数名を「マングル」します。したがって、静的キーワードがないCでは、次の関数が1つしかない場合があります。必要なファイルやライブラリの数に関係なく、プログラム内のそれぞれの一意の名前。

では、既存の以前の関数に関数を変更したい場合はどうしますか?

スマートCコーダーが行うことは、その機能に別の名前を付けることです。しかし、プリプロセッサでソーステキストをプリエンプティブに変更することでコンパイラを「だます」方法があります。

例:一部の馬鹿は、ライブラリにint sort( char** Array) 関数を記述しました。そしてそれをグローバルにしました、そしてそれはバグがあり、あなたが望むことを正確に行いません、なぜならそれは数字が文字か何かの後に来るようにし、そして何らかの理由でTワードが常に最初にあるからです。

ライブラリを使用しますが、関数を修正する必要があります。ソースコードではなく、ヘッダーとコンパイル済みライブラリのみがあります。

OK>したがって、「」のすべてのインスタンスを置き換える「特別な」ヘッダーが作成されます。ヘッダーで「sort」を「bad\_sort」に置き換えてから、コードをインポートし、「sort」のすべてのインスタンスを「good\_sort」に置き換えます。 「good\_sort」はgood\_sort.hで完全に定義されていますが、静的とマークされているため、含まれているファイルでのみ認識されます。

/* good\_sort.h */

#ifndef \_GOOD\_SORT\_H

#define \_GOOD\_SORT\_H

static int good\_sort(char** Array)

{

... //code here

return numsorted;

}

#endif

定義ガードブラケットが追加され、2回含まれないようになっています。

/*-----------------------------------*/

/* program.c */

#include "Trumpsort.h" /* The buggy library header */

...

#ifdef sort

#undef sort /* undefine the sort function name as reserved */

#define sort bad\_sort /* replace the name */

#include "good\_sort.h" /* your fixed version */

#endif

#define sort good\_sort /* replace the name in this file */

/* rest of file */

ちょっとしたくだらないことですが、アイデアは関数を呼び出すことですrenamによる悪いものの代わりにそれを「good\_sort」に呼び出し、代わりにそれを呼び出します。 (ただし、このファイルのみ— 静的)。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です