ANSI Cには名前空間がないのはなぜですか?
-
10-10-2019 - |
質問
名前空間を持つことは、ほとんどの言語では簡単なように思えます。しかし、私が知る限り、Ansi Cはそれをサポートしていません。なぜだめですか?将来の基準にそれを含める計画はありますか?
解決
Cには名前空間があります。 1つは構造タグ用、もう1つは他のタイプ用です。次の定義を検討してください。
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
最初のものはあります 鬼ごっこ foo、および後者はtypedefを使用してタイプFooになります。まだ名前のぶつきは起こりません。これは、構造タグとタイプ(組み込みのタイプとタイプ化されたタイプ)が別々の名前空間に住んでいるためです。
Cが許可していないのは、作成することです 新着 意志による名前空間。 Cは言語で重要であると見なされる前に標準化されており、名前空間を追加することは、正しい動作にマングリングが必要であるため、後方互換性を脅かすでしょう。これは、哲学ではなく、技術のために起因すると思います。
編集:Jeremypは幸運にも私を修正し、私が見逃した名前空間について言及しました。ラベルやストラクチャ/ユニオンメンバーの名前空間もあります。
他のヒント
完全には、Cで名前空間から得られる「利点」を達成する方法がいくつかあります。
私のお気に入りの方法の1つは、構造を使用して、ライブラリなどのインターフェイスである多数のメソッドポインターを収容することです。
次に、すべての機能を指すライブラリ内で初期化するこの構造の外部インスタンスを使用します。これにより、クライアントの名前空間を踏むことなく、ライブラリに名前をシンプルに保つことができます(グローバルスコープでのExtern変数、1変数とおそらく数百の方法を除く)。
追加のメンテナンスが必要ですが、最小限であると感じています。
これが例です:
/* interface.h */
struct library {
const int some_value;
void (*method1)(void);
void (*method2)(int);
/* ... */
};
extern const struct library Library;
/* interface.h */
/* interface.c */
#include "interface.h"
void method1(void)
{
...
}
void method2(int arg)
{
...
}
const struct library Library = {
.method1 = method1,
.method2 = method2,
.some_value = 36
};
/* end interface.c */
/* client code */
#include "interface.h"
int main(void)
{
Library.method1();
Library.method2(5);
printf("%d\n", Library.some_value);
return 0;
}
/* end */
の用法 。構文は、古典的なLibrary_function()Library_Some_Valueメソッドをめぐる強力な関連付けを作成します。ただし、いくつかの制限がありますが、マクロを関数として使用することはできません。
Cには名前空間があります。構文はです namespace_name
. 。そのようにそれらをネストすることさえできます general_specific_name
. 。また、毎回名前空間名を書き留めずに名前にアクセスできるようにしたい場合は、ヘッダーファイルに関連するプリプロセッサマクロを含めます。
#define myfunction mylib_myfunction
これは、名前のマングリングと他の残虐行為よりもはるかにクリーンで、特定の言語は名前空間を配信することを約束します。
歴史的に、cコンパイラは名前をmangleしていません(彼らは窓で行いますが、 cdecl
呼び出し条約は、アンダースコアプレフィックスのみを追加することで構成されています)。
これにより、他の言語(アセンブラーを含む)のCライブラリを簡単に使用でき、よく見る理由の1つです extern "C"
C ++ APIのラッパー。
ただの歴史的な理由。当時、誰も名前空間のようなものを持っているとは考えていませんでした。また、彼らは本当に言語をシンプルにしようとしていました。彼らは将来それを持っているかもしれません
答えではありませんが、コメントではありません。 Cは定義する方法を提供しません namespace
明示的に。範囲が変動します。例えば:
int i=10;
struct ex {
int i;
}
void foo() {
int i=0;
}
void bar() {
int i=5;
foo();
printf("my i=%d\n", i);
}
void foobar() {
foo();
bar();
printf("my i=%d\n", i);
}
変数と関数に適格な名前を使用できます。
mylib.h
void mylib_init();
void mylib_sayhello();
あなたがすることができない名前空間との唯一の違い using
インポートできません from mylib
.
ANSI Cは、名前空間がある前に発明されました。
この機能をCに追加したい人は、コンパイラ著者チームとISOボディに圧力をかけるように組み合わせて組織化されていないからです。
CはC ++のような名前空間をサポートしていません。 C ++ネームスペースの実装は、名前をマングルします。以下に概説するアプローチを使用すると、マングルされていない名前を持つ間、C ++の名前空間の利益を得ることができます。質問の性質は、Cが名前空間をサポートしない理由であることを理解しています(そして、些細な答えは、それが実装されていなかったからではないということです:))。テンプレートと名前空間の機能をどのように実装したかを誰かが見るのに役立つかもしれないと思っただけです。
Cを使用して名前空間やテンプレートの利点を取得する方法に関するチュートリアルを書きました
基本的な名前空間については、名前空間名をコンベンションとして単純に接頭することができます。
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
と書くことができます
struct MY_OBJECT_HANDLE;
struct MY_OBJECT_HANDLE *my_object_init();
void my_object_destroy( MY_OBJECT_HANDLE * & h );
void my_object_do_something(MY_OBJECT_HANDLE *h, ... );
名前の概念とテンプレートの概念を使用する必要がある2番目のアプローチは、マクロ連結を使用して含めることです。たとえば、aを作成できます
template<T> T multiply<T>( T x, T y ) { return x*y }
次のようにテンプレートファイルを使用します
Template.hを掛けます
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
Multiply-Template.C
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
これで、int_multiplyを次のように定義できます。この例では、int_multiply.h/.cファイルを作成します。
int_multiply.h
#ifndef _INT_MULTIPLY_H
#define _INT_MULTIPLY_H
#ifdef _multiply_
#undef _multiply_
#endif
#define _multiply_(NAME) int ## _ ## NAME
#ifdef _multiply_type_
#undef _multiply_type_
#endif
#define _multiply_type_ int
#include "multiply-template.h"
#endif
int_multiply.c
#include "int_multiply.h"
#include "multiply-template.c"
これらすべての最後に、関数とヘッダーファイルがあります。
int int_multiply( int x, int y ) { return x * y }
リンクのリストでどのように機能するかを示すリンクに関するより詳細なチュートリアルを作成しました。うまくいけば、これは誰かを助けます!