为什么ANSI C没有命名空间?

Pul*_*nha 82 c namespaces ansi-c

对于大多数语言来说,拥有名称空间似乎是明智之举.但据我所知,ANSI C不支持它.为什么不?有计划将其纳入未来的标准吗?

小智 87

为了完整起见,有几种方法可以实现从命名空间中获得的"好处",在C中.

我最喜欢的方法之一是使用一个结构来容纳一堆方法指针,它们是你的库/ etc的接口.

然后使用此结构的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 */
Run Code Online (Sandbox Code Playgroud)

指某东西的用途 .语法在经典Library_function()Library_some_value方法上创建强关联.但是有一些限制,因为您不能将宏用作函数.

  • ...当你执行`library.method1()`时,编译器是否足够聪明以在编译时"取消引用"函数指针? (11认同)
  • 这是我在C中见过的最酷的事情之一! (10认同)
  • 这是一个好主意,但你如何处理常量和枚举? (3认同)
  • @AlexReinking:嗯,这很好,但我们永远不会内联这些函数.并且 - necro'ing很棒,不需要道歉. (3认同)
  • 这太棒了。我可能要补充的一件事是,我正在尝试将 `.c` 文件中的所有函数默认设为静态,因此唯一公开的函数是在 `.c` 中的 `const struct` 定义中显式公开的函数文件。 (2认同)
  • @einpoklum - 抱歉死掉,但至少从 6.3.0 版本开始,gcc 将在使用 `-O2` 和 `-flto` 编译时计算 `function1`/`method2` 的实际地址。除非您将此类库与自己的源代码一起编译,否则这种方法会为其函数调用增加一些开销。 (2认同)

小智 58

C确实有名称空间.一个用于结构标签,另一个用于其他类型.考虑以下定义:

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;
Run Code Online (Sandbox Code Playgroud)

第一个是标签 foo,后一个是带有typedef的foo类型.仍然没有发生任何名字冲突.这是因为结构标记和类型(内置类型和typedef'ed类型)位于不同的名称空间中.

C不允许的是按意志创建新的命名空间.在语言被认为是重要的之前,C是标准化的,添加名称空间也会威胁向后兼容性,因为它需要名称修改才能正常工作.我认为这可归因于技术性而非哲学.

编辑:JeremyP幸运地纠正了我并提到了我错过的命名空间.标签和结构/联合成员也有名称空间.

  • 实际上有两个以上的名称空间.除了你提到的两个之外,每个struct和union的成员都有一个名称空间用于标签和名称空间. (6认同)
  • 这可能被称为命名空间,但我相信这些不是OP所询问的那种命名空间. (6认同)
  • 函数的名称空间呢? (2认同)

R..*_*R.. 22

C有名称空间.语法是namespace_name.您甚至可以将它们嵌套在一起general_specific_name.如果您希望每次都能在不写出命名空间名称的情况下访问名称,请在头文件中包含相关的预处理器宏,例如

#define myfunction mylib_myfunction
Run Code Online (Sandbox Code Playgroud)

这比名称修改以及某些语言承诺提供名称空间的其他暴行要清晰得多.

  • 我不知道你怎么能真正支持这个位置.当其他每个系统都有不同的本地黑客来实现命名空间时,请向Javascript社区询问有关集成项目的信息.我从来没有听到有人抱怨'命名空间'或'包'关键字为他们的语言增加了太多的复杂性.另一方面,尝试调试乱码宏的代码可能会变得毛茸茸! (38认同)
  • 我看到的不同了.使语法复杂化,在符号上引入名称修改等,以实现与预处理器一样微不足道的事情,这就是我所说的肮脏的黑客和糟糕的设计. (24认同)
  • 我发现令人兴奋的是,C人实际上会直面争辩.C++中有许多功能,边缘锋利,让人感到悲伤.命名空间不是这些功能之一.他们很棒,他们工作得很好.对于记录而言,预处理器没有什么是微不足道的.最后,demangling名称是微不足道的,有很多命令行实用程序可以为你完成. (17认同)
  • 我听说有很多人抱怨C++名称错误(从调试,工具链,ABI兼容性,动态符号查找等的角度来看)以及不知道特定名称实际指的是什么的复杂性. (5认同)
  • @R ..如果C++中的名称变形被标准化,那就不会发生.仅这一点对ABI兼容性没有帮助,但肯定会修复名称映射问题. (5认同)
  • 这不是命名空间,这是使用命名约定来很难模仿命名空间给你的东西. (4认同)
  • Mangling并不是绝对必要的,仅用于名称空间.您所需要的只是一个不是有效标识符字符的分隔符.Java使用`$`和`.`字符执行此操作,并且嵌套的类名称并不那么难看. (3认同)
  • 如果你不能做`using`,它不是命名空间.如果你不能在`namespace foo {/*等等等*/}中包含定义,那么它不是命名空间. (3认同)
  • 这只是说C没有名称空间的一种愚蠢的方式。根据您的定义,任何在符号中支持_的语言都将支持名称空间。这不是通常在计算中使用“命名空间”一词的方式。 (2认同)

Chr*_*oph 10

从历史上看,C编译器不会破坏名称(它们在Windows上执行,但cdecl调用约定的修改只包含下划线前缀).

这使得从其他语言(包括汇编程序)使用C库变得容易,这也是您经常看到extern "C"C++ API包装器的原因之一.

  • 但为什么会出现这样的问题呢?我的意思是,假设所有命名空间名称都以__da13cd6447244ab9a30027d3d0a08903_开头,然后是名称(那是我刚刚生成的UUID v4)?这可能会破坏使用此特定UUID的名称,但该机会基本上为零.因此实际上不会出现问题错误_only_namespace_names_. (2认同)

lov*_*esh 7

只是历史原因.当时没有人想过有类似命名空间的东西.他们也真的试图保持语言简单.他们将来可能会拥有它

  • 在标准委员会中是否有任何计划在将来向C添加名称空间?迁移到C / C ++模块是否可行,这会使将来变得更容易? (2认同)

Cra*_*rks 5

ANSI C 是在命名空间出现之前发明的。

  • 它是?第一个 ANSI C 规范是 1989 年。我很确定命名空间(以某种形式或另一种形式)在那之前就已经在编程语言中了。例如,Ada 在 1983 年被标准化,并且将包作为命名空间。反过来,这些基本上基于 Modula-2 模块。 (11认同)
  • 我不会将 ANSI C 的发明日期定为它的规范被正式采用时;该语言预先存在,规范只是记录了已经存在的内容。尽管从本网站上的一些答案中,人们可能会认为规范首先出现,第一个编译器是事后才想到的。 (4认同)

kha*_*hik 5

不是答案,而是评论.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);
}
Run Code Online (Sandbox Code Playgroud)

您可以为变量和函数使用限定名称:

mylib.h

void mylib_init();
void mylib_sayhello();
Run Code Online (Sandbox Code Playgroud)

它与名称空间的唯一区别在于它using无法导入和无法导入from mylib.