대부분의 언어에서 네임 스페이스를 사용하는 것은 쉬운 일이 아닙니다. 그러나 내가 말할 수있는 한 ANSI C는 그것을 지원하지 않습니다. 왜 안돼? 향후 표준에 포함시킬 계획이 있습니까?
대부분의 언어에서 네임 스페이스를 사용하는 것은 쉬운 일이 아닙니다. 그러나 내가 말할 수있는 한 ANSI C는 그것을 지원하지 않습니다. 왜 안돼? 향후 표준에 포함시킬 계획이 있습니까?
답변:
C에는 네임 스페이스가 있습니다. 하나는 구조 태그 용이고 다른 하나는 다른 유형용입니다. 다음 정의를 고려하십시오.
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
첫 번째는 foo 태그 가 있고, 나중에는 typedef를 사용하여 foo 유형으로 만들어집니다. 여전히 이름 충돌이 발생하지 않습니다. 이는 구조 태그 및 유형 (내장 유형 및 typedef'ed 유형)이 별도의 네임 스페이스에 있기 때문입니다.
C가 허용하지 않는 것은 의지로 새 네임 스페이스 를 만드는 것입니다. C는 이것이 언어에서 중요하다고 간주되기 전에 표준화되었으며 네임 스페이스를 추가하면 제대로 작동하려면 이름 변경이 필요하기 때문에 이전 버전과의 호환성을 위협 할 수 있습니다. 나는 이것이 철학이 아닌 기술 때문이라고 생각합니다.
편집 : JeremyP는 다행스럽게도 나를 수정하고 내가 놓친 네임 스페이스를 언급했습니다. 레이블 및 struct / union 멤버 용 네임 스페이스도 있습니다.
struct
정의는 구성원에 대한 새 네임 스페이스를 선언합니다. 나는 그 사실을 악용하는 것을 옹호하지 않으며 struct
s는 정적 멤버를 가질 수 없기 때문에 그것을 악용하는 수단을 알지 못합니다.
완전성을 위해 C에서 네임 스페이스에서 얻을 수있는 "이점"을 얻을 수있는 몇 가지 방법이 있습니다.
내가 가장 좋아하는 방법 중 하나는 라이브러리 / 등에 대한 인터페이스 인 여러 메서드 포인터를 수용하는 구조를 사용하는 것입니다.
그런 다음 모든 함수를 가리키는 라이브러리 내부에서 초기화하는이 구조의 extern 인스턴스를 사용합니다. 이를 통해 클라이언트 네임 스페이스를 밟지 않고 라이브러리에서 이름을 단순하게 유지할 수 있습니다 (전역 범위의 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"
C ++ API 용 래퍼를 자주 보는 이유 중 하나입니다 .
대답은 아니지만 코멘트는 아닙니다. 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를 사용하여 네임 스페이스 및 / 또는 템플릿의 이점을 얻는 방법에 대한 자습서를 작성했습니다.
기본 네임 스페이스의 경우 규칙으로 네임 스페이스 이름을 접두사로 지정할 수 있습니다.
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 }
링크 된 목록과 함께 작동하는 방법을 보여주는 링크에 대해 훨씬 더 자세한 자습서를 만들었습니다. 바라건대 이것은 누군가를 도울 것입니다!