对于大多数语言来说,拥有名称空间似乎是理所当然的。但据我所知,ANSI C不支持它。为什么不?有什么计划将其包含在将来的标准中?
对于大多数语言来说,拥有名称空间似乎是理所当然的。但据我所知,ANSI C不支持它。为什么不?有什么计划将其包含在将来的标准中?
Answers:
C确实具有名称空间。一种用于结构标记,另一种用于其他类型。考虑以下定义:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
第一个标记为 foo,第二个标记为 foo,类型为typedef。仍然没有发生名称冲突。这是因为结构标记和类型(内置类型和类型定义的类型)位于单独的命名空间中。
C不允许的是随意创建新的名称空间。在语言C被认为很重要之前就已经对其进行了标准化,并且添加名称空间也将威胁到向后兼容性,因为它需要名称修饰才能正常工作。我认为这可以归因于技术而不是哲学。
编辑:JeremyP幸运地纠正了我,并提到了我错过的名称空间。有标签和结构/联合成员的名称空间。
struct
定义为其成员声明一个新的名称空间。我既不主张利用该事实,也不知道利用该事实的任何方法,因为struct
s不能具有静态成员。
为了完整起见,有几种方法可以从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方法上创建了强大的关联。但是,存在一些限制,对于一个限制,您不能将宏用作函数。
library.method1()
?
.c
默认情况下将文件中的所有函数设为静态,因此公开的唯一函数是文件const struct
定义中显式公开的函数.c
。
function1
/ 的实际地址。除非您将此类库与自己的源代码一起编译,否则此方法将为其函数调用增加一些开销。method2
-O2
-flto
C具有名称空间。语法为namespace_name
。您甚至可以将它们嵌套在中general_specific_name
。而且,如果您希望能够访问名称而不必每次都写出名称空间名称,请在标头文件中包含相关的预处理器宏,例如
#define myfunction mylib_myfunction
这比名称处理和某些语言承诺提供名称空间的其他暴行要干净得多。
从历史上看,C编译器不会修饰名称(它们在Windows上会修饰名称,但会修饰名称 cdecl
调用约定的修改仅包括添加下划线前缀)。
这使得使用其他语言(包括汇编器)的C库变得容易,这也是您经常看到extern "C"
C ++ API封装程序的原因之一。
只是历史原因。没有人想到当时拥有类似名称空间的东西。他们也确实在努力保持语言简单。他们将来可能会拥有
不是答案,而是评论。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(); }
同样重要的最后两行。
ANSI C是在命名空间出现之前发明的。
因为想要将这种功能添加到C中的人们还没有聚在一起,组织起来对编译器作者团队和ISO机构施加了一些压力。
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 }
我在提供的链接上创建了更详细的教程,以显示其如何与链接列表一起使用。希望这可以帮助某人!