Почему ANSI C не имеет пространств имен? - PullRequest
74 голосов
/ 09 декабря 2010

Пространства имен кажутся простыми для большинства языков. Но, насколько я могу судить, ANSI C не поддерживает это. Почему бы и нет? Есть ли планы включить его в будущий стандарт?

Ответы [ 9 ]

75 голосов
/ 16 февраля 2015

Для полноты картины есть несколько способов получить "преимущества", которые вы можете получить из пространств имен, в 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.Однако есть некоторые ограничения, для одного вы не можете использовать макросы в качестве функций.

51 голосов
/ 09 декабря 2010

C имеет пространства имен.Один для тегов структуры, а другой для других типов.Рассмотрим следующее определение:

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

Первое имеет tag foo, а последнее превращается в тип foo с typedef.Все еще никакого столкновения имен не происходит.Это связано с тем, что теги и типы структуры (встроенные типы и типы с определением типа) находятся в отдельных пространствах имен.

То, что С не позволяет, - это создание нового пространства имен по желанию.Си был стандартизирован до того, как это было признано важным в языке, и добавление пространств имен также поставило бы под угрозу обратную совместимость, потому что для правильной работы требуется искажение имен.Я думаю, что это можно объяснить техническими, а не философскими соображениями.

РЕДАКТИРОВАТЬ: JeremyP, к счастью, исправил меня и упомянул пространства имен, которые я пропустил.Существуют пространства имен для меток, а также для членов структуры / объединения.

20 голосов
/ 09 декабря 2010

C имеет пространства имен.Синтаксис namespace_name.Вы можете даже вкладывать их как в general_specific_name.И если вы хотите иметь доступ к именам без записи каждого имени пространства имен каждый раз, включите соответствующие макросы препроцессора в файл заголовка, например,

#define myfunction mylib_myfunction

Это намного чище, чем искажение имен и другиеЗверства, которые определенные языки обязывают доставлять пространства имен.

10 голосов
/ 09 декабря 2010

Исторически сложилось, что компиляторы C не искажают имена (они делают в Windows, но искажение для соглашения о вызовах cdecl состоит только из добавления префикса подчеркивания).

Это упрощает использование Cбиблиотеки других языков (включая ассемблер) и является одной из причин, по которой вы часто видите extern "C" оболочки для API C ++.

7 голосов
/ 09 декабря 2010

только исторические причины. никто не думал о том, чтобы иметь что-то вроде пространства имен в то время. Также они действительно пытались сохранить язык простым. Они могут иметь это в будущем

5 голосов
/ 09 декабря 2010

Не ответ, но не комментарий.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.

4 голосов
/ 01 октября 2015

Потому что люди, которые хотят добавить эту возможность в C, не собрались вместе и не организовали, чтобы оказать некоторое давление на команды разработчиков компиляторов и органы ISO.

3 голосов
/ 09 декабря 2010

ANSI C был изобретен до появления пространств имен.

0 голосов
/ 30 декабря 2017

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 }

с использованием файлов шаблонов следующим образом

множественно-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 }

Я создал гораздо более подробное руководство по предоставленным ссылкам, которое показывает, как оно работает со связанными списками. Надеюсь, это кому-нибудь поможет!

...