名前空間を持つことは、ほとんどの言語にとって非常に簡単なようです。しかし、私が知る限り、ANSI Cはそれをサポートしていません。何故なの?それを将来の標準に含める計画はありますか?
名前空間を持つことは、ほとんどの言語にとって非常に簡単なようです。しかし、私が知る限り、ANSI Cはそれをサポートしていません。何故なの?それを将来の標準に含める計画はありますか?
回答:
Cには名前空間があります。1つは構造タグ用で、もう1つは他のタイプ用です。次の定義を検討してください。
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
最初のものはタグ fooを持ち、後者はtypedefでタイプfooにされます。それでも名前の衝突は起こりません。これは、構造タグと型(組み込み型とtypedefされた型)が別々の名前空間に存在するためです。
Cが許可していないのは、意図的に新しい名前空間を作成することです。Cは、言語でこれが重要であると見なされる前に標準化されました。名前空間を追加すると、名前のマングリングが正しく機能する必要があるため、下位互換性も脅かされます。これは哲学ではなく専門性によるものだと思います。
編集:JeremyPは幸運にも私を修正し、見逃した名前空間について言及しました。ラベルおよび構造体/共用体メンバーの名前空間もあります。
struct
定義は、そのメンバーの新しい名前空間を宣言します。struct
は静的メンバーを持つことができないため、私はその事実を利用することを主張していませんし、それを利用する方法についても知りません。
完全を期すために、Cでは、名前空間から得られる「メリット」を実現する方法がいくつかあります。
私のお気に入りのメソッドの1つは、構造体を使用して、ライブラリなどへのインターフェイスであるメソッドポインターの束を格納することです。
次に、この構造のexternインスタンスを使用して、ライブラリ内で初期化し、すべての関数をポイントします。これにより、クライアントの名前空間を踏むことなく、ライブラリ内で名前をシンプルに保つことができます(グローバルスコープの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メソッドに対する強い関連付けを作成します。ただし、いくつかの制限があります。マクロを関数として使用することはできません。
library.method1()
ですか?
.c
ファイル内のすべての関数をデフォルトで静的にしようとしているため、公開されている関数const struct
は、.c
ファイル内の定義で明示的に公開されている関数だけです。
function1
/ method2
との両方-O2
でコンパイルすると/ の実際のアドレスを計算します-flto
。このようなライブラリを独自のソースとともにコンパイルしない限り、このアプローチでは、関数呼び出しにオーバーヘッドが追加されます。
Cには名前空間があります。構文はnamespace_name
です。のようにネストすることもできgeneral_specific_name
ます。そして、毎回名前空間名を書き出さなくても名前にアクセスできるようにしたい場合は、関連するプリプロセッサマクロをヘッダーファイルに含めます。
#define myfunction mylib_myfunction
これは名前のマングリングよりもはるかにクリーンであり、特定の言語が名前空間の提供を約束する他の残虐行為です。
歴史的に、Cコンパイラは名前をマングルしません(Windowsでは機能しますが、cdecl
呼び出し規約の変換は、アンダースコアのプレフィックスを追加するだけです)。
これにより、他の言語(アセンブラーを含む)のCライブラリを簡単に使用できるようになりextern "C"
、C ++ APIのラッパーがよく見られる理由の1つです。
答えではなく、コメントではありません。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
です。
namespace mylib { void init(); void say_hello(); }
。
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番目のアプローチは、マクロの連結とインクルードを使用することです。たとえば、
template<T> T multiply<T>( T x, T y ) { return x*y }
次のようにテンプレートファイルを使用する
multiply-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 }
リンクされたリストでどのように機能するかを示す、提供されたリンクに関するより詳細なチュートリアルを作成しました。うまくいけば、これは誰かを助けるでしょう!