Для большинства языков наличие пространств имен кажется легкой задачей. Но насколько я могу судить, ANSI C его не поддерживает. Почему нет? Есть ли планы включить его в будущий стандарт?
Для большинства языков наличие пространств имен кажется легкой задачей. Но насколько я могу судить, ANSI C его не поддерживает. Почему нет? Есть ли планы включить его в будущий стандарт?
Ответы:
У C есть пространства имен. Один для структурных тегов и один для других типов. Рассмотрим следующее определение:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Первый имеет тег foo, а второй преобразован в тип foo с typedef. По-прежнему не происходит конфликта имен. Это связано с тем, что структурные теги и типы (встроенные типы и типы с определением типа) находятся в отдельных пространствах имен.
C не позволяет создавать новое пространство имен по своему желанию. C был стандартизирован до того, как это стало считаться важным для языка, и добавление пространств имен также угрожало бы обратной совместимости, потому что для правильной работы требуется искажение имен. Я думаю, это можно объяснить техническими особенностями, а не философией.
РЕДАКТИРОВАТЬ: JeremyP, к счастью, поправил меня и упомянул пропущенные мной пространства имен. Существуют пространства имен для меток, а также для членов структуры / объединения.
struct
определение объявляет новое пространство имен для своих членов. Я не защищаю использование этого факта, и я не знаю никаких средств его использования, поскольку struct
s не может иметь статических членов.
Для полноты картины существует несколько способов добиться «преимуществ», которые вы можете получить от пространств имен в C.
Один из моих любимых методов - это использование структуры для размещения множества указателей на методы, которые являются интерфейсом к вашей библиотеке и т. Д.
Затем вы используете внешний экземпляр этой структуры, который вы инициализируете внутри своей библиотеки, указывая на все ваши функции. Это позволяет вам сохранять ваши имена простыми в вашей библиотеке, не наступая на пространство имен клиентов (кроме переменной 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"
оболочки для API C ++.
просто исторические причины. в то время никто не думал о существовании чего-то вроде пространства имен. Кроме того, они действительно пытались сделать язык простым. У них может быть это в будущем
Не ответ, но не комментарий. 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.
Пространства имен и шаблоны в 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-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
multiply-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 }
Я создал гораздо более подробное руководство по предоставленным ссылкам, которое показывает, как это работает со связанными списками. Надеюсь, это кому-то поможет!