Для большинства языков наличие пространств имен кажется легкой задачей. Но насколько я могу судить, ANSI C его не поддерживает. Почему нет? Есть ли планы включить его в будущий стандарт?
c
namespaces
ansi-c
Pulkit Sinha
источник
источник
Ответы:
У 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-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 }
Я создал гораздо более подробное руководство по предоставленным ссылкам, которое показывает, как это работает со связанными списками. Надеюсь, это кому-то поможет!
источник