简体   繁体   English

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

[英]Why doesn't ANSI C have namespaces?

Having namespaces seems like no-brainer for most languages.对于大多数语言来说,拥有命名空间似乎是不费吹灰之力的。 But as far as I can tell, ANSI C doesn't support it.但据我所知,ANSI C 不支持它。 Why not?为什么不? Any plans to include it in a future standard?有没有计划将其包含在未来的标准中?

For completeness there are several ways to achieve the "benefits" you might get from namespaces, in C. 为了完整起见,有几种方法可以实现从命名空间中获得的“好处”,在C中。

One of my favorite methods is using a structure to house a bunch of method pointers which are the interface to your library/etc.. 我最喜欢的方法之一是使用一个结构来容纳一堆方法指针,它们是你的库/ etc的接口。

You then use an extern instance of this structure which you initialize inside your library pointing to all your functions. 然后使用此结构的extern实例,在库中初始化指向所有函数。 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..) 这允许您在库中保持名称简单,而无需踩到客户端命名空间(除了全局范围的外部变量,1个变量与可能数百个方法......)

There is some additional maintenance involved but I feel that it is minimal. 还有一些额外的维护,但我觉得它很少。

Here is an example: 这是一个例子:

/* 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 */

The use of . 指某东西的用途 。 syntax creates a strong association over the classic Library_function() Library_some_value method. 语法在经典Library_function()Library_some_value方法上创建强关联。 There are some limitations however, for one you can't use macros as functions. 但是有一些限制,因为您不能将宏用作函数。

C does have namespaces. C确实有名称空间。 One for structure tags, and one for other types. 一个用于结构标签,另一个用于其他类型。 Consider the following definition: 考虑以下定义:

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

The first one has tag foo, and the later is made into type foo with a typedef. 第一个是标签 foo,后一个是带有typedef的foo类型。 Still no name-clashing happens. 仍然没有发生任何名字冲突。 This is because structure tags and types (built-in types and typedef'ed types) live in separate namespaces. 这是因为结构标记和类型(内置类型和typedef'ed类型)位于不同的名称空间中。

What C doesn't allow is to create new namespace by will. C不允许的是按意志创建新的命名空间。 C was standardized before this was deemed important in a language, and adding namespaces would also threaten backwards-compatibility, because it requires name mangling to work right. 在语言被认为是重要的之前,C是标准化的,添加名称空间也会威胁向后兼容性,因为它需要名称修改才能正常工作。 I think this can be attributed due to technicalities, not philosophy. 我认为这可归因于技术性而非哲学。

EDIT: JeremyP fortunately corrected me and mentioned the namespaces I missed. 编辑:JeremyP幸运地纠正了我并提到了我错过的命名空间。 There are namespaces for labels and for struct/union members as well. 标签和结构/联合成员也有名称空间。

C has namespaces. C有名称空间。 The syntax is namespace_name . 语法是namespace_name You can even nest them as in general_specific_name . 您甚至可以像在general_specific_name一样嵌套它们。 And if you want to be able to access names without writing out the namespace name every time, include the relevant preprocessor macros in a header file, eg 如果您希望每次都能在不写出命名空间名称的情况下访问名称,请在头文件中包含相关的预处理器宏,例如

#define myfunction mylib_myfunction

This is a lot cleaner than name mangling and the other atrocities certain languages commit to deliver namespaces. 这比名称修改和某些语言承诺提供命名空间的其他暴行要清晰得多。

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编译器不会破坏名称(它们在Windows上执行,但cdecl调用约定的修改只包含下划线前缀)。

This makes it easy to use C libraries from other languages (including assembler) and is one of the reasons why you often see extern "C" wrappers for C++ APIs. 这使得从其他语言(包括汇编程序)使用C库变得容易,这也是您经常看到C ++ API的extern "C"包装器的原因之一。

just historical reasons. 只是历史原因。 nobody thought of having something like a namespace at that time. 当时没有人想过有类似命名空间的东西。 Also they were really trying to keep the language simple. 他们也真的试图保持语言简单。 They may have it in the future 他们将来可能会拥有它

Not an answer, but not a comment. 不是答案,而是评论。 C doesn't provide a way to define namespace explicitly. C没有提供明确定义namespace的方法。 It has variable scope. 它具有可变范围。 For example: 例如:

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);
}

You can use qualified names for variables and functions: 您可以为变量和函数使用限定名称:

mylib.h

void mylib_init();
void mylib_sayhello();

The only difference from namespaces it that you cannot be using and cannot import from mylib . 与命名空间的唯一区别是它无法using且无法from mylib导入。

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

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

You can.你可以。 Like other's answer, define function pointers in a struct.像其他人的答案一样,在结构中定义函数指针。

However, declare it in your header file, mark it static const and initialize it with the corresponding functions.但是,在您的文件中声明它,将其标记为 static const 并使用相应的函数对其进行初始化。 With -O1 or higher it will be optimized as normal function calls使用 -O1 或更高版本,它将作为正常函数调用进行优化

eg:例如:

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

Take advantage of the #include statement so you do not need to define all functions in one single header.利用#include 语句,您无需在一个单独的标题中定义所有函数。

Do not add header guards as you are including it more than once.因为你是不止一次,包括它添加页眉警卫。

eg: header1.h例如:header1.h

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

mylib.h mylib.h

#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"
};

C doesn't support namespaces like C++. C不支持像C ++这样的命名空间。 The implementation of C++ namespaces mangle the names. C ++命名空间的实现破坏了名称。 The approach outlined below allows you to get the benefit of namespaces in C++ while having names that are not mangled. 下面概述的方法允许您使用C ++中的命名空间的好处,同时具有未被破坏的名称。 I realize that the nature of the question is why doesn't C support namespaces (and a trivial answer would be that it doesn't because it wasn't implemented :)). 我意识到问题的本质是为什么C不支持命名空间(并且一个简单的答案是它不会因为它没有实现:))。 I just thought that it might help someone to see how I've implemented the functionality of templates and namespaces. 我只是认为它可以帮助别人看到我如何实现模板和命名空间的功能。

I wrote up a tutorial on how to get the advantage of namespaces and/or templates using C. 我写了一篇关于如何使用C获得命名空间和/或模板优势的教程。

Namespaces and templates in C C中的命名空间和模板

Namespaces and templates in C (using Linked Lists) 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, ... );
}

can be written as 可写成

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

A second approach that I have needed that uses the concept of namespacing and templates is to use the macro concatenation and include. 我需要使用命名空间和模板概念的第二种方法是使用宏连接和包含。 For example, I can create a 例如,我可以创建一个

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

using template files as follows 使用模板文件如下

multiply-template.h 乘template.h

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

multiply-template.c 乘template.c

_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
  return x*y;
}

We can now define int_multiply as follows. 我们现在可以如下定义int_multiply。 In this example, I'll create a int_multiply.h/.c file. 在这个例子中,我将创建一个int_multiply.h / .c文件。

int_multiply.h 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 int_multiply.c

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

At the end of all of this, you will have a function and header file for. 在所有这些结束时,您将拥有一个函数和头文件。

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

I created a much more detailed tutorial on the links provided which show how it works with linked lists. 我在提供的链接上创建了一个更详细的教程,展示了它如何与链表一起使用。 Hopefully this helps someone! 希望这有助于某人!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM