ANSI C에 네임 스페이스가없는 이유는 무엇입니까?


92

대부분의 언어에서 네임 스페이스를 사용하는 것은 쉬운 일이 아닙니다. 그러나 내가 말할 수있는 한 ANSI C는 그것을 지원하지 않습니다. 왜 안돼? 향후 표준에 포함시킬 계획이 있습니까?


13
C ++를 네임 스페이스가있는 C로 사용하십시오!
AraK 2010

3
나는 물론 할 수있다,하지만, 난 여전히 같은 알 수있는 것
Pulkit 신하

5
2 가지. 불필요한 고유 구문 : 네임 스페이스가있는 다른 모든 언어는 '.'만 사용합니다. '.'의 다른 사용과 모호하지 않기 때문에 구분 기호로. 그리고 더 비판적으로 C ++는 범위 지정 using 지시문을 도입하지 않았습니다. 이는 프로그래머가 네임 스페이스를 전역 범위로 가져 오기 위해 지시문을 과도하게 사용했음을 의미합니다. 이는 C ++ 표준위원회가 이제 std ::에 새로운 기능을 추가 할 수 없음을 의미합니다. 결과적으로 중단되는 코드의 양이 분할을 중복으로 만들었 기 때문입니다.
Chris Becke

2
@Chris Becke : 저는 독특한 구문을 좋아합니다. 이름 공간에서 클래스를보고 있는지 클래스의 멤버를보고 있는지 알고 싶습니다.
JeremyP 2010

6
@ChrisBecke, 이것은 몇 년 늦었지만 C ++ 네임 스페이스가 제대로 구현되지 않았기 때문에 C로 구현해서는 안된다고 주장하는 것이 흥미 롭습니다. 그런 다음 다른 언어가 C ++의 끊김없이 구현한다는 점에 주목하세요. 다른 언어를 할 수 있다면, 왜 하지 그들 C에 소개?
weberc2 2014 년

답변:


68

C에는 네임 스페이스가 있습니다. 하나는 구조 태그 용이고 다른 하나는 다른 유형용입니다. 다음 정의를 고려하십시오.

struct foo
{
    int a;
};

typedef struct bar
{
    int a;
} foo;

첫 번째는 foo 태그 가 있고, 나중에는 typedef를 사용하여 foo 유형으로 만들어집니다. 여전히 이름 충돌이 발생하지 않습니다. 이는 구조 태그 및 유형 (내장 유형 및 typedef'ed 유형)이 별도의 네임 스페이스에 있기 때문입니다.

C가 허용하지 않는 것은 의지로 네임 스페이스 를 만드는 것입니다. C는 이것이 언어에서 중요하다고 간주되기 전에 표준화되었으며 네임 스페이스를 추가하면 제대로 작동하려면 이름 변경이 필요하기 때문에 이전 버전과의 호환성을 위협 할 수 있습니다. 나는 이것이 철학이 아닌 기술 때문이라고 생각합니다.

편집 : JeremyP는 다행스럽게도 나를 수정하고 내가 놓친 네임 스페이스를 언급했습니다. 레이블 및 struct / union 멤버 용 네임 스페이스도 있습니다.


8
실제로 두 개 이상의 네임 스페이스가 있습니다. 언급 한 두 가지 외에도 각 구조체 및 공용체의 구성원에 대한 레이블 및 이름 공간에 대한 이름 공간이 있습니다.
JeremyP 2010

@JeremyP : 수정 해 주셔서 감사합니다. 난 단지 내가 표준 :-) 확인하지 않았다, 메모리 떨어져 쓴

2
함수의 네임 스페이스는 어떻습니까?
themihai

8
이것은 네임 스페이스라고 부를 수 있지만, OP가 요구하는 네임 스페이스의 종류가 아니라고 생각합니다.
avl_sweden

1
@jterm 아니요. 나는 C 기능을 해킹하는 것을 옹호하는 것이 아니라 단지 사실만을 언급한다. 각 struct정의는 구성원에 대한 새 네임 스페이스를 선언합니다. 나는 그 사실을 악용하는 것을 옹호하지 않으며 structs는 정적 멤버를 가질 수 없기 때문에 그것을 악용하는 수단을 알지 못합니다.
JeremyP

99

완전성을 위해 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 메서드에 대한 강력한 연관성을 만듭니다. 그러나 몇 가지 제한 사항이 있지만 매크로를 함수로 사용할 수 없습니다.


12
... 컴파일러는 컴파일 타임에 함수 포인터를 "역 참조"할만큼 똑똑합니까 library.method1()?
einpoklum

1
정말 대단해요. 추가 할 수있는 한 가지는 .c기본적으로 내 파일의 모든 함수를 정적으로 만들려고한다는 것입니다 . 따라서 노출되는 유일한 함수 const struct.c파일 의 정의에 명시 적으로 노출 된 것 입니다.
lastmjs

3
좋은 생각이지만 상수와 열거 형을 어떻게 처리합니까?
nowox

1
@einpoklum - 미안 괴사가에, 그러나 적어도 버전 6.3.0의로, GCC는 실제 주소를 계산합니다 function1/ method2모두 컴파일 할 때 -O2-flto. 자체 소스와 함께 이러한 라이브러리를 컴파일하지 않는 한이 방법은 함수 호출에 약간의 오버 헤드를 추가합니다.
Alex Reinking 2018 년

3
@AlexReinking : 글쎄요, 좋지만 우리는 이러한 함수를 인라인하지 않을 것입니다. 그리고-네크로 잉은 훌륭합니다. 사과 할 필요가 없습니다.
einpoklum

24

C에는 네임 스페이스가 있습니다. 구문은 namespace_name입니다. 에서와 같이 중첩 할 수도 있습니다 general_specific_name. 매번 네임 스페이스 이름을 작성하지 않고 이름에 액세스 할 수 있도록하려면 헤더 파일에 관련 전 처리기 매크로를 포함합니다.

#define myfunction mylib_myfunction

이것은 이름 맹 글링과 특정 언어가 네임 스페이스를 제공하는 다른 잔학 행위보다 훨씬 더 깨끗합니다.


24
나는 그것을 다르게 본다. 문법을 복잡하게하고, 기호에 이름을 맹 글링하는 등 전처리기로 이미 사소한 일을 달성하기 위해 내가 더러운 해킹과 형편없는 디자인이라고 부르는 것입니다.
R .. GitHub STOP HELPING ICE

41
나는 당신이 어떻게 그 위치를 정말로 지원할 수 있을지 모르겠습니다. 다른 모든 시스템에 네임 스페이스 구현을위한 자체 해킹이 다른 경우 프로젝트 통합에 대해 Javascript 커뮤니티에 문의하십시오. 나는 '네임 스페이스'또는 '패키지'키워드가 그들의 언어에 너무 많은 복잡성을 추가하는 것에 대해 불평하는 사람을 들어 본 적이 없습니다. 반면에 매크로가 흩어져있는 코드를 디버깅하는 것은 매우 빠르게 진행될 수 있습니다!
weberc2 2013

5
많은 사람들이 C ++ 이름 맹 글링 (디버깅, 도구 체인, ABI 호환성, 동적 기호 조회 등의 관점에서)과 특정 이름이 실제로 무엇을 가리키는 지 알지 못하는 복잡성에 대해 불평하는 것을 들었습니다.
R .. GitHub의 STOP 돕기 ICE

6
@R .. C ++의 이름 변경이 표준화 된 경우에는 발생하지 않습니다. 이것만으로는 ABI 호환성에 도움이되지 않지만 이름 매핑 문제를 확실히 해결할 수 있습니다.
Malcolm

20
나는 C 사람들이 실제로 이것을 똑 바른 얼굴로 논쟁 할 것이라는 점이 마음에 들었습니다. C ++에는 사람들에게 슬픔을주는 날카로운 모서리가있는 많은 기능이 있습니다. 네임 스페이스는 이러한 기능 중 하나가 아닙니다. 그들은 훌륭하고 아주 잘 작동합니다. 그리고 기록을 위해 전처리 기가 사소한 것은 없습니다. 마지막으로 이름을 분해하는 것은 사소한 일이며이를 수행 할 수있는 명령 줄 유틸리티가 많이 있습니다.
Nir Friedman

12

역사적으로 C 컴파일러는 이름을 변경하지 않습니다 (Windows에서 수행하지만 cdecl호출 규칙에 대한 맹 글링 은 밑줄 접두사 추가로만 구성됨).

이로 인해 다른 언어 (어셈블러 포함)의 C 라이브러리를 쉽게 사용할 수 있으며 extern "C"C ++ API 용 래퍼를 자주 보는 이유 중 하나입니다 .


2
그런데 그게 왜 그런 문제일까요? 내 말은, 모든 네임 스페이스 이름이 _da13cd6447244ab9a30027d3d0a08903으로 시작 하고 그 다음 이름 (방금 생성 한 UUID v4)이라고 가정합니다. 이 특정 UUID를 사용하는 이름을 깨뜨릴 가능성이 있지만 그 기회는 본질적으로 0입니다. 따라서 실제로 only_namespace_names를 맹 글링하는 데 문제가 없습니다 .
einpoklum

7

단지 역사적인 이유. 당시에는 아무도 네임 스페이스 같은 것을 생각하지 않았습니다. 또한 그들은 언어를 단순하게 유지하려고 노력했습니다. 그들은 미래에 그것을 가질 수 있습니다


2
앞으로 C에 네임 스페이스를 추가하려는 표준위원회의 움직임이 있습니까? C / C ++ 모듈로 이동하면 앞으로 더 쉽게 할 수 있습니까?
lanoxx

1
@lanoxx 이전 버전과의 호환성 때문에 C에 네임 스페이스를 추가 할 의지가 없습니다.
themihai

6

대답은 아니지만 코멘트는 아닙니다. 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) 마지막 두 줄을 바꿀 수 없습니다 .
einpoklum

3

ANSI C는 네임 스페이스가 생성되기 전에 발명되었습니다.


10
그랬어? 최초의 ANSI C 사양은 1989 년이었습니다. 나는 네임 스페이스 (어떤 형태로든)가 그 전에 프로그래밍 언어로되어 있었다고 확신합니다. 예를 들어 Ada는 1983 년에 표준화되었으며 패키지를 네임 스페이스로 사용했습니다. 차례로 그것들은 본질적으로 Modula-2 모듈을 기반으로했습니다.
그냥 내 정확한 OPINION

4
나는 ANSI C의 발명이 공식적으로 채택 된 때로 날짜를 정하지 않을 것이다. 언어는 미리 존재했고 사양은 이미 존재하는 것을 문서화했습니다. 이 사이트의 일부 답변에서 사양이 먼저 왔고 첫 번째 컴파일러가 사후 고려 사항이라고 생각할 수 있습니다.
Crashworks

ANSI C는 ANSI C 이전과 몇 가지 중요한 차이점이 있지만 네임 스페이스는 그중 하나가 아닙니다.
dan04

한편 나는 네임 스페이스가 등장한 훨씬 뒤인 2020 년에 글을 쓰고있다. 최신 C 표준에는 여전히 이러한 기능이 없습니다. C가 말이되는만큼 이것은 심하게 빠진 기능 중 하나입니다.

3

이 기능을 C에 추가하려는 사람들이 함께 모여서 컴파일러 작성자 팀과 ISO 본문에 압력을 가하지 않았기 때문입니다.


1
C에서 네임 스페이스는이 사람들이 스스로를 구성하고 네임 스페이스 지원으로 확장을 생성하는 경우에만 볼 수 있다고 생각합니다. 그러면 ISO 기관은 선택의 여지가 없으며 표준으로 게시 할 수 있습니다 (다소 변경됨). 이것이 자바 스크립트 (이 점에서 C와 유사한 점이 있음)가 한 방식입니다.
themihai

3
@themihai : "확장 프로그램 만들기"= gcc 및 clang 사람들이 네임 스페이스를 컴파일하도록합니다.
einpoklum

1

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 }

링크 된 목록과 함께 작동하는 방법을 보여주는 링크에 대해 훨씬 더 자세한 자습서를 만들었습니다. 바라건대 이것은 누군가를 도울 것입니다!


3
링크는 네임 스페이스를 추가하는 방법을 설명합니다. 그러나 문제는 네임 스페이스가 지원되지 않는 이유였습니다. 따라서이 답변은 답변이 아니며 대신 주석이어야합니다.
그리고 나는
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.