ANSI Cに名前空間がないのはなぜですか?


91

名前空間を持つことは、ほとんどの言語にとって非常に簡単なようです。しかし、私が知る限り、ANSI Cはそれをサポートしていません。何故なの?それを将来の標準に含める計画はありますか?


13
C-with-namespaceとしてC ++を使用してください!
AraK

3
もちろんできますが、それでも知りたいのですが
Pulkit Sinha

5
2つのこと。不必要な特有の構文:名前空間を持つ他のすべての言語は「。」のみを使用します セパレータとして、他の「。」の使用とあいまいではありません。さらに重要なことに、c ++はスコープ付きusingディレクティブを導入していません。これは、プログラマーがディレクティブを使用して名前空間をグローバルスコープにインポートしすぎたことを意味します。つまり、c ++標準委員会は今ではstd ::に新しい機能を追加できないため、結果として壊れるコードの量によってパーティション分割が冗長になっています。
Chris Becke

2
@Chris Becke:私は独特の構文が好きです。名前空間のクラスを見ているのか、クラスのメンバーを見ているのか知りたいです。
JeremyP 2010

6
@ChrisBecke、これは数年遅れですが、C ++の名前空間は十分に実装されていないため、Cで実装するべきではないと主張するのは興味深いことです。次に、他の言語がC ++のハングアップなしに実装することに注意してください。他の言語がそれを行うことができるなら、なぜそれらをCに導入しませんか?
weberc2 2013年

回答:


67

Cには名前空間があります。1つは構造タグ用で、もう1つは他のタイプ用です。次の定義を検討してください。

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

最初のものはタグ fooを持ち、後者はtypedefでタイプfooにされます。それでも名前の衝突は起こりません。これは、構造タグと型(組み込み型とtypedefされた型)が別々の名前空間に存在するためです。

Cが許可していないのは、意図的に新しい名前空間を作成することです。Cは、言語でこれが重要であると見なされる前に標準化されました。名前空間を追加すると、名前のマングリングが正しく機能する必要があるため、下位互換性も脅かされます。これは哲学ではなく専門性によるものだと思います。

編集:JeremyPは幸運にも私を修正し、見逃した名前空間について言及しました。ラベルおよび構造体/共用体メンバーの名前空間もあります。


8
実際には3つ以上の名前空間があります。あなたが言及した2つに加えて、ラベルの名前空間と、各構造体と共用体のメンバーの名前空間があります。
JeremyP

@JeremyP:訂正ありがとうございます。私はこれをオフメモリに書き込んだだけで、標準をチェックしませんでした:-)

2
関数の名前空間はどうですか?
themihai

8
これは名前空間と呼ばれることもありますが、これらはOPが要求していた名前空間の種類ではないと私は思います。
avl_sweden 2017

1
@jtermいいえ。私はCの機能をハッキングすることを主張するのではなく、事実を述べるだけです。各struct定義は、そのメンバーの新しい名前空間を宣言します。structは静的メンバーを持つことができないため、私はその事実を利用することを主張していませんし、それを利用する方法についても知りません。
JeremyP

98

完全を期すために、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メソッドに対する強い関連付けを作成します。ただし、いくつかの制限があります。マクロを関数として使用することはできません。


12
...そして、コンパイラは、コンパイル時に関数ポインタを「逆参照」するのに十分賢いlibrary.method1()ですか?
einpoklum

1
これはとても素晴らしいです。追加できることの1つは、.cファイル内のすべての関数をデフォルトで静的にしようとしているため、公開されている関数const structは、.cファイル内の定義で明示的に公開されている関数だけです。
lastmjs 2017

3
それは素晴らしいアイデアですが、定数と列挙型をどのように処理しますか?
nowox 2017

1
@einpoklum-ネクロに申し訳ありませんが、少なくともバージョン6.3.0以降、gccはfunction1/ method2との両方-O2でコンパイルすると/ の実際のアドレスを計算します-flto。このようなライブラリを独自のソースとともにコンパイルしない限り、このアプローチでは、関数呼び出しにオーバーヘッドが追加されます。
Alex Reinking 2018年

3
@AlexReinking:まあ、それはいいことですが、これらの関数をインライン化することは決してできません。そして-壊死は素晴らしいです、謝罪は必要ありません。
einpoklum 2018年

24

Cには名前空間があります。構文はnamespace_nameです。のようにネストすることもできgeneral_specific_nameます。そして、毎回名前空間名を書き出さなくても名前にアクセスできるようにしたい場合は、関連するプリプロセッサマクロをヘッダーファイルに含めます。

#define myfunction mylib_myfunction

これは名前のマングリングよりもはるかにクリーンであり、特定の言語が名前空間の提供を約束する他の残虐行為です。


24
見方が違う。文法を複雑にし、シンボルに名前のマングリングを導入するなど、プリプロセッサですでに簡単なことを達成することは、私が汚いハックと貧弱なデザインと呼んでいるものです。
R .. GitHub STOP

40
どうすればその立場を本当にサポートできるかわかりません。他のすべてのシステムに、名前空間を実装するための独自のハックがある場合、プロジェクトの統合についてJavascriptコミュニティに質問してください。「名前空間」または「パッケージ」というキーワードが言語に複雑さを加えすぎることについて不平を言う人は聞いたことがありません。一方、マクロが散らばっているコードをデバッグしようとすると、非常に速くなります。
weberc2 2013

5
C ++の名前の変換(デバッグ、ツールチェーン、ABI互換性、動的シンボル検索などの観点から)や、特定の名前が実際に何を参照しているのかわからないという複雑さについて不満を言う人はたくさんいます。
R .. GitHub STOP HELPING ICE 2013

6
@R .. C ++でマングリングする名前が標準化されている場合、これは起こりません。これだけではABIの互換性には役立ちませんが、名前のマッピングの問題は確実に修正されます。
マルコム

19
Cの人々が実際にこれをまっすぐな顔で主張することは心を打たれることに心を打たれる。C ++には、人々に悲しみを与える鋭いエッジを持つ多くの機能があります。名前空間はこれらの機能の1つではありません。彼らは素晴らしいです、彼らはとてもよく働きます。そして、記録のために、プリプロセッサで何も簡単なことはありません。最後に、名前をデマングルするのは簡単です。それを行うコマンドラインユーティリティがたくさんあります。
Nir Friedman

12

歴史的に、Cコンパイラは名前をマングルしません(Windowsでは機能しますが、cdecl呼び出し規約の変換は、アンダースコアのプレフィックスを追加するだけです)。

これにより、他の言語(アセンブラーを含む)のCライブラリを簡単に使用できるようになりextern "C"、C ++ APIのラッパーがよく見られる理由の1つです。


2
しかし、なぜそのような問題があるのでしょうか。つまり、すべての名前空間の名前が_da13cd6447244ab9a30027d3d0a08903始まり、次に名前(つまり、生成したばかりのUUID v4)で始まるとしましょう。これにより、この特定のUUIDを使用する名前が壊れる可能性がありますが、その可能性は本質的にゼロです。したがって、実際にはonly_namespace_namesの変換に問題はありません。
einpoklum

7

歴史的な理由だけです。当時は誰も名前空間のようなものを考えていませんでした。また、彼らは本当に言語をシンプルに保つことを試みていました。彼らは将来それを持つかもしれません


2
標準委員会で将来的に名前空間をCに追加する動きはありますか?C / C ++モジュールへの移行により、これは将来的に簡単になる可能性がありますか?
lanoxx

1
@lanoxx下位互換性の理由から、名前空間をCに追加する予定はありません。
themihai

6

答えではなく、コメントではありません。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です。


また、最後の2行を置き換えることもできませんnamespace mylib { void init(); void say_hello(); }
einpoklum、2015年

3

ANSI Cは、名前空間の前に発明されました。


10
そうだった?最初のANSI C仕様は1989年でした。その前に、何らかの形で名前空間がプログラミング言語に含まれていたと確信しています。たとえば、Adaは1983年に標準化され、名前空間としてパッケージがありました。これらは、基本的にModula-2モジュールに基づいていました。
私の正しい意見だけ

4
ANSI Cの発明については、その仕様が正式に採用されたときまで日付を記入しません。言語は事前に存在し、仕様にはすでにそこに何があったかが文書化されています。このサイトの回答のいくつかから、仕様が最初に来て、最初のコンパイラが後付けとして考えられるかもしれません。
Crashworks、2010

ANSI Cは、ANSI C以前とはいくつかの大きな違いがありましたが、名前空間はそれらの1つではありませんでした。
dan04

3

この機能をCに追加したい人々が集まって組織化されていないため、コンパイラー作成者チームとISO本体にプレッシャーをかけています。


1
Cでの名前空間は、これらの人々が自分自身を編成し、名前空間をサポートする拡張機能を作成する場合にのみ見られると思います。次に、ISO機関は選択肢を持たず、標準として公開します(多少の変更はあります)。これがjavascript(この点でCといくつかの類似点がある)が行った方法です。
themihai 2016

3
@themihai:「拡張を作成する」= gccとclangの人々に名前空間をコンパイルしてもらいます。
einpoklum 2016

1

CはC ++のような名前空間をサポートしていません。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 }

リンクされたリストでどのように機能するかを示す、提供されたリンクに関するより詳細なチュートリアルを作成しました。うまくいけば、これは誰かを助けるでしょう!


3
リンクは、名前空間を追加する方法を説明しています。ただし、問題は、名前空間がサポートされていない理由でした。したがって、この回答は回答ではなく、コメントにする必要があります。
トーマスウェラー2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.