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


91

对于大多数语言来说,拥有名称空间似乎是理所当然的。但据我所知,ANSI C不支持它。为什么不?有什么计划将其包含在将来的标准中?


13
使用C ++作为带有命名空间的C!
AraK 2010年

3
我当然可以,但是我仍然想知道
Pulkit Sinha

5
2件事。不必要的特殊语法:具有名称空间的所有其他语言都只使用“。”。作为分隔符,因为它与'。'的其他用法没有歧义。而且,更重要的是,C ++从未引入范围化的using指令。这意味着程序员过度使用指令将命名空间导入全局范围。这意味着c ++标准委员会现在无法向std ::添加新功能,因为由此可能会中断的代码量使分区变得多余。
克里斯·贝克

2
@克里斯·贝克:我喜欢独特的语法。我想知道我是在看名称空间中的类还是在类中的成员。
JeremyP 2010年

6
@ChrisBecke,这已经晚了几年,但是有趣的是,您认为C ++名称空间实现不佳,因此不应在C中实现它们。然后您会注意到其他语言在没有C ++中断的情况下实现了它们。如果其他语言可以做到,为什么将它们介绍给C?
weberc2

Answers:


67

C确实具有名称空间。一种用于结构标记,另一种用于其他类型。考虑以下定义:

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

第一个标记为 foo,第二个标记为 foo,类型为typedef。仍然没有发生名称冲突。这是因为结构标记和类型(内置类型和类型定义的类型)位于单独的命名空间中。

C不允许的是随意创建新的名称空间。在语言C被认为很重要之前就已经对其进行了标准化,并且添加名称空间也将威胁到向后兼容性,因为它需要名称修饰才能正常工作。我认为这可以归因于技术而不是哲学。

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


8
实际上有两个以上的名称空间。除了您提到的两个之外,还有用于标签的名称空间以及用于每个结构和联合的成员的名称空间。
JeremyP 2010年

@JeremyP:非常感谢您的纠正。我只是在记忆中写下了这个,我没有检查标准:-)

2
函数的名称空间呢?
themihai '16

8
这很可能称为名称空间,但我相信这些不是OP所要求的名称空间。
avl_sweden

1
@jterm不。我并不是在主张黑客C功能,而是在陈述事实。每个struct定义为其成员声明一个新的名称空间。我既不主张利用该事实,也不知道利用该事实的任何方法,因为structs不能具有静态成员。
JeremyP

98

为了完整起见,有几种方法可以从C语言中的名称空间中获得“好处”。

我最喜欢的方法之一是使用一种结构来容纳一堆方法指针,这些方法指针是您的库等的接口。

然后,您可以使用此结构的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 2015年

1
太棒了 我可能要添加的一件事是,我尝试.c默认情况下将文件中的所有函数设为静态,因此公开的唯一函数是文件const struct定义中显式公开的函数.c
lastmjs '02

3
那是个好主意,但是您如何处理常量和枚举呢?
nowox

1
@einpoklum-对necro表示歉意,但至少从6.3.0版开始,gcc 在与和一起编译时将计算function1/ 的实际地址。除非您将此类库与自己的源代码一起编译,否则此方法将为其函数调用增加一些开销。method2-O2-flto
亚历克斯·雷肯

3
@AlexReinking:很好,但是我们永远不会内联这些函数。而且-死灵化很棒,无需道歉。
einpoklum

24

C具有名称空间。语法为namespace_name。您甚至可以将它们嵌套在中general_specific_name。而且,如果您希望能够访问名称而不必每次都写出名称空间名称,请在标头文件中包含相关的预处理器宏,例如

#define myfunction mylib_myfunction

这比名称处理和某些语言承诺提供名称空间的其他暴行要干净得多。


24
我有不同的看法。我将这种语法复杂化,在符号上引入名称修饰等来实现与预处理器已经微不足道的工作,这就是我所说的肮脏的技巧和糟糕的设计。
R .. GitHub停止帮助ICE

40
我看不出您如何真正支持该职位。当其他每个系统都有不同的本地方法来实现名称空间时,请向Javascript社区询问有关集成项目的信息。我从未听说过有人抱怨'namespace'或'package'关键字为其语言增加了太多复杂性。另一方面,尝试调试杂乱无章的代码会很快变得毛茸茸!
weberc2

5
我听说很多人抱怨C ++名称修饰(从调试,工具链,ABI兼容性,动态符号查找等角度来看)以及不知道特定名称实际上是指什么的复杂性。
R .. GitHub停止帮助ICE

6
@R。如果将C ++中的名称处理标准化,则不会发生。仅此一项就无助于ABI兼容性,但肯定会解决名称映射问题。
马尔科姆

19
我感到很震惊,C人士实际上会以直言不讳地争论这一点。C ++中有许多功能,这些功能具有令人生畏的尖锐边缘。命名空间不是这些功能之一。他们很棒,运作良好。记录下来,对于预处理器来说,没有什么是微不足道的。最后,取消名称的名称很简单,有很多命令行实用程序可以帮您完成。
弗里德曼

12

从历史上看,C编译器不会修饰名称(它们在Windows上会修饰名称,但会修饰名称 cdecl调用约定的修改仅包括添加下划线前缀)。

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


2
但是为什么会这样呢?我的意思是,假设所有命名空间名称都以_da13cd6447244ab9a30027d3d0a08903开头,然后是名称(那是我刚刚生成的UUID v4)?可能会破坏使用该特定UUID的名称,但该机会实际上为零。因此,在实践中,处理only_namespace_names不会有问题。
einpoklum 2015年

7

只是历史原因。没有人想到当时拥有类似名称空间的东西。他们也确实在努力保持语言简单。他们将来可能会拥有


2
在标准委员会中是否有任何将来向C添加名称空间的动议?迁移到C / C ++模块是否可能,这将来会使它变得更容易吗?
lanoxx

1
@lanoxx由于向后兼容的原因,没有意愿向C添加名称空间。
themihai 2016年

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


您也不能替换namespace mylib { void init(); void say_hello(); }同样重要的最后两行。
einpoklum 2015年

3

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


10
它是?第一个ANSI C规范是1989年。我可以肯定的是,在那之前,命名空间(以某种形式或其他形式)是使用编程语言编写的。例如,Ada于1983年进行了标准化,并将程序包作为名称空间。这些反过来又基本上基于Modula-2模块。
只是我的正确观点2010年

4
我不会将ANSI C的发明追溯到正式采用它的规范。该语言是预先存在的,而规范仅记录了已经存在的内容。尽管从该站点上的一些答案中可能会认为规范是第一位的,后来才想到了第一个编译器。
Crashworks 2010年

ANSI C与之前的ANSI C确实有一些显着差异,但名称空间不是其中之一。
dan04 2011年

3

因为想要将这种功能添加到C中的人们还没有聚在一起,组织起来对编译器作者团队和ISO机构施加了一些压力。


1
我认为只有在这些人能够自己组织起来并创建具有名称空间支持的扩展时,我们才能看到C中的名称空间。然后,ISO机构别无选择,只能将它们作为标准发布(有或多或少的更改​​)。这就是javascript(在这方面与C有一些相似之处)的实现方式。
themihai

3
@themihai:“创建扩展名” =让gcc和clang人员编译名称空间。
einpoklum's

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, ... );

我需要使用命名空间和模板概念的第二种方法是使用宏串联和包含。例如,我可以创建一个

template<T> T multiply<T>( T x, T y ) { return x*y }

使用模板文件如下

乘法模板

_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);

乘法模板

_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
您的链接说明了如何添加名称空间。但是,问题是为什么不支持名称空间。因此,此答案不是答案,而应该是评论。
托马斯·韦勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.