Наявність простору імен здається незрозумілим для більшості мов. Але, наскільки я можу зрозуміти, ANSI C цього не підтримує. Чому ні? Будь-які плани включити його до майбутнього стандарту?
Наявність простору імен здається незрозумілим для більшості мов. Але, наскільки я можу зрозуміти, ANSI C цього не підтримує. Чому ні? Будь-які плани включити його до майбутнього стандарту?
Відповіді:
C має простори імен. Один для тегів структури, а другий для інших типів. Розглянемо наступне визначення:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
Перший має тег foo, а пізній перетворюється на type foo за допомогою typedef. Досі не відбувається конфлікту імен. Це тому, що теги та типи структури (вбудовані типи та типи, визначені типом) живуть в окремих просторах імен.
Те, що C не дозволяє, - це створювати новий простір імен за заповітом. C був стандартизований до того, як це було визнано важливим у мові, і додавання просторів імен також загрожувало б зворотній сумісності, оскільки для правильної роботи потрібно керувати іменами. Думаю, це можна пояснити технічними особливостями, а не філософією.
EDIT: 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(); }
що також важливо (ish).
ANSI C був винайдений раніше просторів імен.
Тому що люди, які хочуть додати цю можливість до C, не зібралися та не організували певного тиску на авторські групи компіляторів та на органи ISO.
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 }
Я створив набагато докладніший підручник із наданих посилань, який показує, як це працює зі зв’язаними списками. Сподіваємось, це комусь допомагає!