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

对于大多数语言来说,拥有名称空间似乎是显而易见的。但据我所知,ANSI C 并不支持它。为什么不呢?有计划在未来的标准中包括它吗?

93979 次浏览

只是历史原因。当时没有人想到要有一个像名称空间这样的东西。而且他们真的在努力保持语言的简洁。他们以后可能会有

ANSI C was invented before namespaces were.

不是回答,也不是评论。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

C 确实有名称空间。一个用于结构标记,一个用于其他类型。考虑下面的定义:

struct foo
{
int a;
};


typedef struct bar
{
int a;
} foo;

第一个具有 标签 foo,后一个具有 typedef,用于制作 type foo。还是没有互相指责的事情发生。这是因为结构标记和类型(内置类型和 typedef 类型)存在于单独的名称空间中。

C 语言不允许按意愿创建 新的名称空间。在 C 被认为在语言中很重要之前,C 就已经标准化了,并且添加名称空间也会威胁到向后兼容性,因为它需要名称错误处理才能正常工作。我认为这可以归因于技术细节,而不是哲学。

编辑: JeremyP fortunately corrected me and mentioned the namespaces I missed. There are namespaces for labels and for struct/union members as well.

Historically, C compilers don't mangle names (they do on Windows, but the mangling for the cdecl calling convention consists of only adding an underscore prefix).

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

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

#define myfunction mylib_myfunction

这比某些语言为交付名称空间而进行的名称篡改和其他暴行要干净得多。

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

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

You then use an extern instance of this structure which you initialize inside your library pointing to all your functions. This allows you to keep your names simple in your library without stepping on the clients namespace (other than the extern variable at global scope, 1 variable vs possibly hundreds of methods..)

有一些额外的维护涉及,但我觉得它是最小的。

这里有一个例子:

/* 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 方法上创建强关联。但是也有一些限制,比如不能使用宏作为函数。

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

C 不支持 C + + 这样的名称空间。C + + 名称空间的实现混淆了名称。下面概述的方法使您能够在 C + + 中获得名称空间的好处,同时不会损坏名称。我意识到问题的实质是为什么 C 不支持名称空间(一个简单的答案是不支持,因为它没有实现:)。我只是觉得它可以帮助别人了解我是如何实现模板和名称空间的功能的。

I wrote up a tutorial on how to get the advantage of namespaces and/or templates using C.

C 中的名称空间和模板

C 语言中的命名空间和模板(使用链表)

For the basic namespace, one can simply prefix the namespace name as a convention.

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

我需要的第二种使用名称空间和模板概念的方法是使用宏连接和 include。例如,我可以创建一个

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 _ multi.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

整数乘法

#include "int_multiply.h"
#include "multiply-template.c"

在所有这一切结束时,您将有一个函数和头文件。

int int_multiply( int x, int y ) { return x * y }

我创建了一个更加详细的教程提供的链接,显示如何与链表工作。希望这能帮到别人!

You can. Like other's answer, define function pointers in a struct.

但是,在 header文件中声明它,将其标记为静态 const,并使用相应的函数对其进行初始化。 With -O1 or higher it will be optimized as normal function calls

例如:

void myfunc(void);
    

static const struct {
void(*myfunc)(void);
} mylib = {
.myfunc = myfunc
};

利用 # include 语句,这样就不需要在一个头中定义所有函数。

not添加头保护,因为你包括它不止一次。

标题1.h

#ifdef LIB_FUNC_DECL
void func1(void);
#elif defined(LIB_STRUCT_DECL)
struct {
void(*func)(void);
} submodule1;
#else
.submodule1.func = func1,
#endif

亲爱的

#define LIB_FUNC_DECL
#include "header1.h"
#undef LIB_FUNC_DECL
#define LIB_STRUCT_DECL


static const struct {
#include "header1.h"
#undef LIB_STRUCT_DECL
} mylib = {
#include "header1.h"
};