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

时间:2010-12-09 08:14:56

标签: c namespaces ansi-c

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

9 个答案:

答案 0 :(得分:74)

为了完整起见,有几种方法可以实现"效益"你可能会从命名空间中获得,在C。

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

然后使用此结构的extern实例,在库中初始化指向所有函数。这使您可以在库中保持名称简单,而无需踩到客户端命名空间(除了全局范围的外部变量,1个变量与可能数百个方法......)

还有一些额外的维护,但我觉得它很少。

以下是一个例子:

/* interface.h */

struct library {
    const int some_value;
    void (*function1)(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方法上创建强关联。但是,有一些限制,因为您不能将宏用作函数。

答案 1 :(得分:51)

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

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

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

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

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

答案 2 :(得分:19)

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

#define myfunction mylib_myfunction

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

答案 3 :(得分:10)

从历史上看,C编译器不会破坏名称(它们在Windows上运行,但cdecl调用约定的重​​整只包括添加下划线前缀)。

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

答案 4 :(得分:6)

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

答案 5 :(得分: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);
}

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

mylib.h

void mylib_init();
void mylib_sayhello();

与命名空间的唯一区别是,您不能using且无法导入from mylib

答案 6 :(得分:4)

因为想要为C添加此功能的人没有聚在一起组织起来给编译器作者团队和ISO机构施加压力。

答案 7 :(得分:3)

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

答案 8 :(得分:-1)

C不支持像C ++这样的命名空间。 C ++命名空间的实现破坏了名称。下面概述的方法允许您使用C ++中的命名空间的好处,同时具有未被破坏的名称。我意识到这个问题的本质是为什么C不支持命名空间(并且一个简单的答案是它不会因为它没有被实现:)。我只是认为可以帮助别人了解我是如何实现模板和命名空间的功能的。

我写了一篇关于如何使用C.

获得命名空间和/或模板优势的教程

Namespaces and templates in C

Namespaces and templates in C (using Linked Lists)

对于基本命名空间,可以简单地将命名空间名称作为约定加上前缀。

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 }

使用模板文件如下

乘法template.h

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

乘法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 }

我在提供的链接上创建了一个更详细的教程,展示了它如何与链表一起使用。希望这有助于某人!