C ++ 식별자에서 밑줄을 사용하는 것에 대한 규칙은 무엇입니까?


930

C ++에서는 지역 변수 또는 매개 변수가 아닌 구성원 변수라는 사실을 나타 내기 위해 접두어를 사용하여 구성원 변수의 이름을 지정하는 것이 일반적입니다. MFC 배경에서 온 경우 아마도을 사용 m_foo합니다. 나는 또한 myFoo때때로 보았다 .

C # (또는 .NET)은 밑줄 만 사용하는 것이 좋습니다 _foo. 이것이 C ++ 표준에서 허용됩니까?


3
그에 대한 glibc는 매뉴얼 페이지에서 찾을 수 있습니다 gnu.org/software/libc/manual/html_node/Reserved-Names.html 편집 : 참조 opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
— CesarB

6
이러한 규칙을 무지한다고해서 코드가 컴파일되거나 실행되지 않는다는 것을 의미하지는 않지만 코드가 다른 컴파일러 및 버전으로 이식되지 않을 가능성이 높습니다. 충돌합니다. 이것을 뒷받침하기 위해 나는 어디에서나 대문자로 명명 규칙으로 사용 된 중요한 시스템의 특정 구현을 알고 있습니다. 이로 인해 오류가없는 곳이 있습니다. 물론 나쁜 습관입니다.
— g24l

답변:


852

규칙 (C ++ 11에서는 변경되지 않음) :

  • 구현 매크로 로 사용하는 것을 포함하여 모든 범위에서 예약됩니다 .
    • 밑줄로 시작하고 바로 대문자가 나오는 식별자
    • 인접한 밑줄 (또는 "이중 밑줄")을 포함하는 식별자
  • 글로벌 네임 스페이스에 예약 됨 :
    • 밑줄로 시작하는 식별자
  • 또한 std네임 스페이스의 모든 것이 예약되어 있습니다. (그러나 템플릿 전문화를 추가 할 수 있습니다.)

2003 C ++ 표준에서 :

17.4.3.1.2 전역 이름 [lib.global.names]

특정 이름 및 함수 서명 세트는 항상 구현에 예약되어 있습니다.

  • 이중 밑줄 ( __)을 포함하거나 밑줄로 시작하고 대문자 (2.11)로 시작 하는 각 이름 은 모든 사용을 위해 구현에 예약되어 있습니다.
  • 밑줄로 시작하는 각 이름은 전역 네임 스페이스에서 이름으로 사용하기 위해 구현에 예약되어 있습니다. 165

165) 이러한 이름은 네임 스페이스 ::std(17.4.3.1) 에도 예약되어 있습니다 .

C ++는 C 표준 (1.1 / 2, C ++ 03)을 기반으로하고 C99는 표준 참조 (1.2 / 1, C ++ 03)이므로 1999 C 표준에서 적용됩니다.

7.1.3 예약 식별자

각 헤더는 관련 하위 조항에 나열된 모든 식별자를 선언 또는 정의하며, 선택적으로 관련 미래 라이브러리 지침 하위 조항 및 식별자에 항상 나열된 모든 식별자 또는 파일 범위 식별자로 사용하도록 예약 된 식별자를 선언하거나 정의합니다.

  • 밑줄과 대문자 또는 다른 밑줄로 시작하는 모든 식별자는 항상 사용하도록 예약되어 있습니다.
  • 밑줄로 시작하는 모든 식별자는 항상 일반 네임 스페이스와 태그 네임 스페이스 모두에서 파일 범위를 가진 식별자로 사용되도록 예약되어 있습니다.
  • 다음 하위 조항 (향후 라이브러리 지시 사항 포함)의 각 매크로 이름은 연관된 헤더가 포함 된 경우 지정된대로 사용하도록 예약되어 있습니다. 달리 명시되지 않는 한 (7.1.4 참조)
  • 다음 하위 조항 중 하나에서 외부 연계가있는 모든 식별자 (향후 라이브러리 지시 사항 포함)는 항상 외부 연계가있는 식별자로 사용되도록 예약되어 있습니다. 154
  • 다음 하위 조항 중 하나에 나열된 파일 범위가있는 각 식별자 (향후 라이브러리 지시 사항 포함)는 매크로 이름으로 사용되며 연관된 헤더가 포함 된 경우 동일한 네임 스페이스에서 파일 범위가있는 식별자로 예약됩니다.

다른 식별자는 예약되어 있지 않습니다. 프로그램이 예약 된 컨텍스트에서 식별자를 선언하거나 정의하거나 (7.1.4에서 허용하지 않은 경우) 예약 된 식별자를 매크로 이름으로 정의하면 동작이 정의되지 않습니다.

프로그램이 #undef위에 나열된 첫 번째 그룹에서 식별자의 매크로 정의를 (와 함께 ) 제거 하면 동작이 정의되지 않습니다.

154) 외부 링크 예약 식별자리스트가 포함되어 errno, math_errhandling, setjmp, 및 va_end.

다른 제한 사항이 적용될 수 있습니다. 예를 들어 POSIX 표준은 일반 코드에 표시 될 수있는 많은 식별자를 보유합니다.

  • E대문자로 시작하는 이름 은 숫자 나 대문자를 따릅니다.
    • 추가 오류 코드 이름에 사용될 수 있습니다.
  • 소문자로 시작 is하거나 to뒤에 오는 이름
    • 추가 문자 테스트 및 변환 기능에 사용될 수 있습니다.
  • LC_대문자로 시작하는 이름
    • 로케일 속성을 지정하는 추가 매크로에 사용될 수 있습니다.
  • 접미사가 붙 f거나 l예약 된 모든 기존 수학 함수의 이름
    • float 및 long double 인수에서 각각 작동하는 해당 함수의 경우
  • SIG대문자로 시작하는 이름 은 예약되어 있습니다
    • 추가 신호 이름.
  • SIG_대문자로 시작하는 이름 은 예약되어 있습니다
    • 추가 신호 동작.
  • 로 시작하는 이름 str, mem또는 wcs소문자 문자 다음은 예약되어 있습니다
    • 추가 문자열 및 배열 함수
  • 소문자로 시작 PRI하거나 SCN뒤에 오는 이름 또는 X예약 된 이름
    • 추가 형식 지정자 매크로
  • 로 끝나는 이름 _t은 예약되어 있습니다
    • 추가 유형 이름.

현재이 이름을 자신의 목적으로 사용하면 문제가 발생하지 않을 수 있지만 향후 해당 표준 버전과 충돌 할 가능성이 있습니다.


개인적으로 나는 밑줄로 식별자를 시작하지 않습니다. 내 규칙에 새로운 추가 사항 : 밑줄을 거의 사용하지 않으므로 쉽게 이중 밑줄을 사용하지 마십시오.

이 기사에 대한 연구를 한 후에 _t 는 POSIX 표준에 의해 예약되어 있으므로 더 이상 식별자를 끝내지 않습니다 .

로 끝나는 식별자에 대한 규칙은 _t저 를 놀라게했습니다. 나는 그것이 명확하고 공식적인 장과 절을 찾고있는 POSIX 표준 (아직 확실하지 않다)이라고 생각한다. 이것은 예약 된 이름을 나열한 GNU libtool 매뉴얼 에서 가져온 것 입니다.

CesarB는 POSIX 2004 예약 기호 에 대한 다음 링크를 제공했으며 '다른 많은 예약 된 접두사 및 접미사를 찾을 수 있습니다.' POSIX 2008 예약 된 기호는 여기에 정의되어 있습니다. 제한은 위의 제한보다 약간 미묘합니다.


14
C ++ 표준은 C 표준을 "가져 오지"않습니다. 그들은 내가 아는 한 특정 헤더를 가져 오지만 언어 전체 또는 명명 규칙은 아닙니다. 그러나 _t는 저를 놀라게했습니다. 그러나 C이기 때문에 전역 n에만 적용 할 수 있습니다. _t를 클래스 안에서 읽을 때 안전해야합니다
— jalf

27
C ++ 표준은 C 표준을 "가져 오지"않습니다. 이 참조 는 C 표준을. C ++ 라이브러리 소개에 "라이브러리는 표준 C 라이브러리의 기능을 사용할 수 있습니다"라고 말합니다. C 표준 라이브러리의 헤더를 적절하게 변경하여 포함 시키지만 "가져 오는"방법은 아닙니다. C ++ 표준에는 예약 된 이름을 설명하는 고유 한 규칙 세트가 있습니다. C로 예약 된 이름을 C ++로 예약해야한다면 이것이 바로 여기에 있습니다. 그러나 C ++ 표준은 그렇게 말하지 않습니다. 그래서 C에 예약 된 것들이 C ++에 예약되어 있다고 생각하지 않습니다.하지만 잘못되었을 수 있습니다.
— Johannes Schaub-litb

8
이것이 "_t"문제에 대해 내가 찾은 것입니다. n1256 (C99 TC3)의 말 : "intdef 또는 int로 시작하고 _t로 끝나는 typedef 이름은 예약되어 있습니다." 나는 여전히 "foo_t"와 같은 이름을 사용할 수 있다고 생각하지만 POSIX에 의해 예약 된 것으로 생각합니다.
— Johannes Schaub-litb

59
POSIX는 'tolerance'를 'to'+ 소문자로 시작하여 예약합니까? 많은 규칙이이 규칙을 어 기고 있다고 확신합니다!
— Sjoerd

23
@LokiAstari, " C ++ 표준은 C 표준으로 정의됩니다. 기본적으로 C ++는 이러한 차이점과 추가 사항이있는 C라고합니다. "넌센스! C ++는 [basic.fundamental] 및 라이브러리의 C 표준 만 참조합니다. 당신이 말하는 사실이라면, 여기서 C는 그런 말 ++ 않습니다 _Bool및 _ImaginaryC ++에 존재하지 않는? C ++ 언어는 C에 대한 "편집"이 아니라 명시 적으로 정의됩니다. 그렇지 않으면 표준이 훨씬 짧을 수 있습니다!
— Jonathan Wakely

198

이름 충돌을 피하는 규칙은 C ++ 표준 (Stroustrup 책 참조)과 C ++ 전문가 (Sutter 등)가 언급 한 것입니다.

개인 규칙

나는 사건을 다루고 싶지 않고 간단한 규칙을 원했기 때문에 간단하고 올바른 개인 을 설계했습니다 .

심볼 이름을 지정할 때 다음과 같은 경우 컴파일러 / OS / 표준 라이브러리와의 충돌을 피할 수 있습니다.

  • 밑줄로 기호를 시작하지 마십시오
  • 안에 두 개의 연속 밑줄이있는 기호의 이름을 지정하지 마십시오.

물론 고유 한 네임 스페이스에 코드를 넣으면 충돌을 피하는 데 도움이됩니다 (그러나 악의적 인 매크로로부터 보호하지는 않음)

몇 가지 예

(매크로는 C / C ++ 기호의 코드 오염이 많기 때문에 매크로를 사용하지만 변수 이름에서 클래스 이름에 이르기까지 다양 할 수 있습니다)

#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT

C ++ 0x 초안에서 추출

로부터 n3242.pdf의 파일 (나는 유사한 것으로 최종 표준 텍스트 예상) :

17.6.3.3.2 전역 이름 [global.names]

특정 이름 및 함수 서명 세트는 항상 구현에 예약되어 있습니다.

— 이중 밑줄 _ _을 포함하거나 밑줄로 시작하고 대문자 (2.12)로 시작하는 각 이름은 사용을 위해 구현에 예약되어 있습니다.

— 밑줄로 시작하는 각 이름은 전역 네임 스페이스에서 이름으로 사용하기 위해 구현에 예약되어 있습니다.

또한 :

17.6.3.3.5 사용자 정의 리터럴 접미사 [usrlit.suffix]

밑줄로 시작하지 않는 리터럴 접미어 식별자는 향후 표준화를 위해 예약되어 있습니다.

글로벌 네임 스페이스에 정의 되지 않은 경우 하나의 밑줄로 시작하고 그 뒤에 소문자가 오는 이름을 고려하지 않는 한이 마지막 절은 혼란 스럽습니다 .


9
@Meysam : __WRONG_AGAIN__두 개의 연속 밑줄 (처음에는 두 개, 끝에는 두 개)이 포함되어 있으므로 표준에 따라 잘못되었습니다.
— paercebal

8
@ BЈовић은 : WRONG__WRONG이 잘못 있도록 표준에 따라, 두 개의 연속 밑줄 (중간에 2 개씩) 포함
— paercebal

2
고유 한 네임 스페이스에 코드를 넣으면 충돌을 피하는 데 도움이됩니다 . 그러나 식별자가 범위와 상관없이 키워드와 충돌 할 수 있기 때문에 (예 : __attribute__GCC) 여전히 충분하지 않습니다 .
— Ruslan

1
표준에 따라 중간 에 두 개의 연속 밑줄이 생기는 데 왜 문제가 있습니까? 사용자 정의 리터럴 접미어는 1234567L또는 4.0f; 와 같은 리터럴 값에 적용됩니다 . IIRC 이것은 ohttp : //en.cppreference.com/w/cpp/language/user_literal을 참조
— Jason S

2
Why is there any problem of having two consecutive underscores in the middle according to the standard?표준에 따르면 예약되어 있다고 말합니다. 이것은 좋지 않은 스타일에 대한 조언 이 아닙니다 . 표준 의 결정 입니다. 그들은 왜 이것을 결정 했습니까? 첫 번째 컴파일러는 표준화 전에 이미 이러한 규칙을 비공식적으로 사용했다고 생각합니다.
— paercebal

38

에서 MSDN :

식별자의 시작 부분에 두 개의 순차적 밑줄 문자 (__) 또는 대문자로 뒤 따르는 단일 밑줄 문자를 사용하면 모든 범위에서 C ++ 구현을 위해 예약됩니다. 현재 또는 미래의 예약 식별자와 충돌 할 수 있으므로 파일 범위 이름의 경우 밑줄 하나와 밑줄을 사용하지 마십시오.

즉, 소문자가 오는 한 단일 밑줄을 멤버 변수 접두어로 사용할 수 있습니다.

이것은 분명히 C ++ 표준의 17.4.3.1.2 섹션에서 가져 왔지만 온라인으로 전체 표준의 원본을 찾을 수는 없습니다.

이 질문 도 참조하십시오 .


2
"17.6.3.3.2 글로벌 이름"나는 섹션에서 (C + +0 표준의 초안) n3092.pdf에서 유사한 텍스트를 발견
— paercebal

7
흥미롭게도 이것은 질문에 대한 직접적이고 간결한 답변이있는 유일한 답변 인 것 같습니다.
— hyde

9
@hyde : 사실, 전역 네임 스페이스에 밑줄이있는 식별자가없는 규칙을 건너 뛰기 때문에 그렇지 않습니다. Roger의 답변을 참조하십시오 . C ++ 표준에 대한 권한으로 MS VC 문서의 인용에 대해 매우주의를 기울였습니다.
— sbi

@ sbi 나는이 답변에서 "단일 밑줄을 멤버 변수 접두어로 사용하여 소문자가 있는 한 멤버 변수 접두어로 사용할 수 있습니다"라고 언급 했습니다. 텍스트의 벽에.
— hyde

5
첫째, 여전히 동일한 규칙이 전역 네임 스페이스에 적용되지 않는다는 힌트가 없다고 생각합니다. 더 나쁜 것은 인접한 밑줄은 식별자 의 시작뿐만 아니라 어디에서나 금지되어 있다는 것 입니다. 따라서이 답변은 사실을 생략하는 것이 아니라 실제로 하나 이상의 적극적으로 잘못된 주장을합니다. 내가 말했듯이 MSVC 문서를 언급하는 것은 VC에 대한 질문이 아니라면 내가하지 않을 것입니다.
— sbi

25

질문의 다른 부분은 변수 이름 의 끝에 밑줄을 두어 내부와 충돌하지 않는 것이 일반적 입니다.

클래스와 네임 스페이스에서도이 작업을 수행합니다. "글로벌 범위의 이름 끝과 다른 곳의 이름 시작"과 비교할 때 하나의 규칙 만 기억하면됩니다.


2

그렇습니다. 밑줄은 식별자의 어느 곳에 나 사용될 수 있습니다. 규칙은 첫 번째 문자의 az, AZ, _ 및 다음 문자의 + 0-9 중 하나입니다.

밑줄 접두사는 C 코드에서 일반적입니다. 단일 밑줄은 "개인"을 의미하며 이중 밑줄은 일반적으로 컴파일러에서 사용하도록 예약되어 있습니다.


3
그것들은 도서관에서 일반적입니다. 사용자 코드에서 공통적이지 않아야합니다.
— Martin York

43
사람들 은 C로 라이브러리를 작성합니다.
— John Millikin

7
"예, 밑줄은 식별자의 어느 곳에 나 사용될 수 있습니다." 이것은 전역 식별자에 잘못되었습니다. Roger의 답변을 참조하십시오 .
— sbi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.