検索
ホームページphp教程PHP开发C/C++のexternキーワードの詳細説明

1 基本的な説明: extern は変数または関数の前に配置して、変数または関数の定義が別のファイルにあることを示し、コンパイラーがこの変数または関数に遭遇したときに他のモジュールでその定義を見つけるように促します。また、extern はリンク指定にも使用できます。

つまり、extern には 2 つの関数があります。まず、extern "C" void fun(int a, int b); のように、"C" と一緒に使用すると、変換時に関数 fun をコンパイルするように指示されます。関数名は、C++ ではなく C の規則に従って、関数名を変換すると、認識できない名前に変更されます。これは、fun@aBc_int_int#%$ などになります。これはコンパイラの「性質」に依存します (コンパイラごとに異なる方法が採用されています)。C++ は関数のオーバーロードをサポートしているため、ここではあまり説明しません。興味がある場合は検索してください。オンラインで、満足のいく説明が得られると思います。
次に、ヘッダー ファイルなどで extern が変数または関数を変更するために使用されない場合、その機能は関数を宣言することです。 function グローバル変数のスコープ キーワード、それによって宣言された関数および変数は、このモジュールまたは他のモジュールで使用できます。つまり、モジュール B (コンパイル ユニット) が参照する場合は、宣言であることに注意してください。モジュール (コンパイル単位) A でグローバル変数または関数が定義されている場合、モジュール A のヘッダー ファイルをインクルードするだけで済みます。コンパイル段階では、モジュール B は関数または変数を見つけることができませんが、エラーは報告されません。接続時にモジュール A から関数または変数を取得します。この関数は生成されたオブジェクト コード内にあります。

2 質問: extern 変数
ソースファイルで配列が定義されています: char a[6];
別のファイルで次のステートメントで宣言されています: extern char *a;
すみません、これでいいですか?
答えと分析:
1)、いいえ、プログラムは実行中に不正アクセスを通知します。その理由は、型 T へのポインターは型 T の配列と同等ではないためです。 extern char *a は文字配列ではなくポインター変数を宣言しているため、実際の定義とは異なり、実行時に不正アクセスが発生します。宣言を extern char a[ ] に変更する必要があります。
2) 解析例は以下の通り a[] = "abcd" の場合、外部変数 a=0x61626364 (abcd の ASCII コード値)、*a は明らかに無意味です
明らかに a が指すスペース (0x61626364)。意味がなく、不正なメモリアクセスが発生しやすい。
3) これは、extern を使用する場合、宣言の形式に厳密に対応する必要があることを思い出させます。実際のプログラミングでは、このようなエラーはよくあります。
4) extern は変数宣言でよく使われます。このグローバル変数を参照したい場合は、 *.h に入れて extern で宣言します。

3 問題: extern 関数のプロトタイプが変更された場合
関数提供者が関数のプロトタイプを一方的に変更した場合、ユーザーがそれを知らずに元の extern 宣言を使い続けた場合、コンパイラはコンパイル中にエラーを報告しません。しかし、運用中に入力パラメータの不足または過剰によりシステムエラーが発生することがよくありますが、この状況はどのように解決すればよいでしょうか。
回答と分析:
現在、業界にはこの状況に対処するための完璧なソリューションがありません。通常のアプローチは、プロバイダーが独自の xxx_pub.h で外部インターフェイスの宣言を提供し、呼び出し元がヘッダーをインクルードすることです。ファイルなので、extern ステップをスキップします。このエラーを回避するには。
剣には両刃があり、externの適用には状況に応じて異なる方法を選択する必要があります。

4 質問: extern "C"
C++ 環境で C 関数を使用する場合、コンパイラーが obj モジュールで C 関数定義を見つけられず、リンクが失敗することがよくあります。この状況を解決するにはどうすればよいですか?

答えと分析:
コンパイル時に関数のポリモーフィズムの問題を解決するために、C++言語は関数名とパラメータを組み合わせて中間関数名を生成しますが、C言語はそうではないので、途中で見つかりません。対応する関数の場合、この時点で C 関数を extern "C" でリンクする必要があります。これはコンパイラに、私の名前を保持し、リンク用の中間関数名を生成しないように指示します。
以下が標準的な書き方です:
//.hファイルの先頭
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */


// .h ファイルの終了場所
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

5 質問: extern 関数宣言
extern は関数の前に置かれ、関数宣言の一部になることがよく見られます。では、C 言語のキーワード extern は関数の宣言においてどのような役割を果たしますか。
答えと分析:
キーワード extern が関数の宣言に含まれている場合、それはその関数が他のソース ファイルで定義できることを意味するだけで、他の効果はありません。つまり、次の 2 つの関数宣言の間に明らかな違いはありません:
extern int f(); と int f();
もちろん、この種の使用法は依然として存在します。つまり、次の関数の代わりにプログラム内で関数を宣言します。 include "*.h"。一部の複雑なプロジェクトでは、すべての関数宣言の前に extern 変更を追加することに慣れています。これを行う理由と長所と短所は、次の例で見ることができます: 「extern で変更されたグローバル変数」

(1) test1.h には次のステートメントがあります:
#ifndef TEST1H
#define TEST1H
extern char g_str[]; //グローバル変数g_str
を宣言 void fun1();
#endif
(2) test1.cpp内 #include "test1.h"
char g_str[] = "123456"; variable g_str
void fun1() { cout (3) 上記は test2 モジュールもあり、コンパイルして接続することができます。 g_str、元のファイルに追加するだけです
#include "test1.h"

void fun2() { cout 上記の test1 と test2興味がある場合は、ultraEdit を使用して test1.obj を開くと、文字列「123456」が見つかりますが、test2.obj には見つかりません。はプロジェクト全体のグローバル変数であり、メモリ内には 1 つのコピー test2 のみが存在します。.obj コンパイル ユニットの別のコピーは必要ありません。そうしないと、接続中に重複定義エラーが報告されます。
(4)定義忘れを防ぐために、グローバル変数の宣言と定義をまとめて記述することを好む人もいます。たとえば、上記の test1.h を
extern char g_str[] = "123456"; に変更します。 extern はありません
次に、test1.cpp の g_str の定義を削除し、2 つのモジュール test1 と test2 をコンパイルして接続すると、ヘッダー ファイルの後にグローバル変数 g_str の定義を配置したため、接続エラーが報告されます。 test1.cpp モジュールには test1.h が含まれているため、g_str が一度定義され、test2.cpp にも test1.h が含まれているため、g_str が再度定義されます。今回は、コネクタは test1 と test2 を接続するときに 2 つの g_str を見つけます。 g_str の定義を test1.h に含める必要がある場合は、test2 のコードから #include "test1.h" を削除し、次のように置き換えます。
extern char g_str[];
void fun2() { cout 現時点では、コンパイラは g_str が外部コンパイル モジュールであることを認識しているため、このモジュールではそれを再度定義しません。これは、#include を使用できないためです。 test2.cpp 内の「test1.h」では、extern で変更しない限り、test1.h で宣言された他の関数を使用できません。この場合、宣言した関数だけが長いリストになり、ヘッダー ファイルの関数になります。外部使用のためのインターフェイスを提供することです。そのため、ヘッダー ファイル内で宣言を行うだけであることを覚えておいてください。真実は常に単純です。
6. extern と static

(1) extern は、変数が別の場所で定義されており、その変数をここで使用することを示します。

(2) static は、メモリを割り当てるときに、静的領域に格納されます。

静的スコープは内部的に接続されており、オブジェクト自体とは別個に保存され、extern も別個に保存されますが、extern を使用して他のオブジェクトから参照することもできます。 static は使用できず、オブジェクト自体のみが使用を許可されます。具体的な違いは、第一に、static と extern は「互換性のない」ペアであることです。つまり、extern と static は同時に変数を変更できません。 、 static によって変更されたグローバル変数の宣言は、定義が同時に実行されることとは異なります。つまり、 static を使用してヘッダー ファイルでグローバル変数を宣言すると、その変数も同時に定義されます。静的に変更されたグローバル変数のスコープは、独自のコンパイル単位のみにすることができます。つまり、スコープ「Global」はこのコンパイル単位に対してのみ有効であり、他のコンパイル単位からは参照できません。たとえば、

(1) test1.h:
#ifndef TEST1H
#define TEST1H
static char g_str[] = "123456"
void fun1 ();
#endif
;

(2) test1.cpp:
#include "test1.h"
void fun1() { cout (3) test2.cpp
#include "test1.h"
void fun2() { cout test1.obj を開くと、文字列「123456」が見つかります。これらは、test2.obj でも見つかります。重複定義エラーが報告されずに正常に接続できる理由は、2 つの異なる変数の割り当てと同じように、内容は同じですが、格納されている物理アドレスが異なるためです。は同じ値を持ち、これら 2 つの変数はそれぞれのコンパイル単位で動作します。 おそらく、あなたはもっと真剣に、上記のコードをこっそりトレースしてデバッグした結果、2 つのコンパイル単位 (test1、test2) の g_str のメモリ アドレスが同じであることがわかり、静的に変更された変数も動作できると結論付けるでしょう。他のモジュールについても説明していますが、コンパイラはあなたを騙していると言いたいのです。ほとんどのコンパイラは、さまざまなモジュールを接続するときにメモリを節約し、実行効率を高めるターゲット プログラムを生成するという目標を達成するためのコードの最適化機能を備えています。場合によっては、上記の「123456」など、同じ内容を持つメモリのコピーが 1 つだけコピーされるため、2 つのコンパイル ユニットにある変数は同じ内容を持つため、接続時にメモリにコピーが 1 つだけ存在します。ここで、上記のコードを次のように変更すると、コンパイラの嘘をすぐに暴露できます:
(1) test1.cpp:
#include "test1.h"
void fun1()
{
g_str[ 0] = '' a '';
Cout & lt; & lt; g_str & lt; endl;}}

#include "test1.h"

void fun2 () ; & lt ; g_str (3) void main() {
fun2() // 123456
; 2 コンパイル単位の g_str アドレスが同じではありません。1 か所で変更したため、コンパイラは強制的に元のメモリに復元されます。2 つのモジュールの変数のコピーがメモリ内に 2 つあります。 static には上記の特性があるため、他のモジュールに不要な情報を汚染しないように、static グローバル変数を定義する場合はヘッダー ファイルではなく元のファイルに配置するのが一般的です。

7. extern と const

C++ の const で変更されたグローバル定数は、static と同じ特性を持っています。つまり、このコンパイル済みモジュール内でのみ使用できますが、const を extern とともに使用して定数が可能であることを宣言できます。 extern const char g_str[]; などのモジュール内で使用できます: const char g_str[] = "123456";

したがって、const が使用される場合は、それを元のファイルで定義することを忘れないでください。単体ではstaticと同じで、externと併用すると連携時もexternと特性が同じになります!したがって、const についてはあまり言う必要はありません。const char* g_str = "123456" は const char g_str[] = "123465" とは異なるということを思い出していただきたいと思います。その g_str は定数ではなく、定義されたグローバル変数 (他のコンパイル単位で使用できる) とみなされます。そのため、char*g_str を const グローバル定数の規則に準拠させたい場合は、次のように const を定義するのが最善です。 char* const g_str="123456".



C/C++ の extern キーワードに関するその他の関連記事については、PHP 中国語 Web サイトに注目してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール