콘 스트 이전 또는 콘 스트 이후?


145

시작하기 위해 아마도 const객체의 데이터 또는 포인터를 수정할 수 없거나 두 가지 모두로 만드는 데 사용될 수 있음을 알고있을 것입니다 .

const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer

그러나 다음 구문을 사용할 수도 있습니다.

Object const *obj; // same as const Object* obj;

중요한 것은 별표에서 const키워드 를 넣는 부분입니다 . 개인적으로 const유형의 왼쪽에 데이터를 수정할 수 없음을 지정하는 것이 좋습니다. 왼쪽에서 오른쪽으로의 사고 방식에서 더 잘 읽히지 만 어떤 구문이 먼저 나왔습니까?

더 중요한 것은 왜 const데이터 를 지정하는 두 가지 올바른 방법이 있으며 어떤 상황에서 어떤 상황에서 하나를 선호하거나 필요합니까?

편집하다:

그래서 컴파일러가 물건을 해석하는 방법에 대한 표준이 내가 태어나 기 오래 전에 작성되었을 때 이것은 임의의 결정이었습니다. 이후 const나는 그들이 추가에 전혀 해를 끼치 없었다 생각 추측 (기본적으로?) 키워드의 왼쪽에 무엇에 적용된다 "바로 가기" 선언에 의해 변경 등의 시간까지 적어도 다른 방법으로 키워드를 입력 한정자를 적용하는가 * 또는 & 구문 분석

이것은 C의 경우에도 마찬가지였습니다.


9
매크로에서 항상 추가 const 한 후 예, 유형 #define MAKE_CONST(T) T const대신 #define MAKE_CONST(T) const T그 때문에 MAKE_CONST(int *)제대로으로 확장됩니다 int * const대신 const int *.
jotik

6
이 두 스타일을 "east const"와 "west const"라고합니다.
Tom Anderson

13
@TomAnderson하지만 실제로는 "east const"와 "const west"여야합니다.
YSC

답변:


96

const데이터 를 지정하는 두 가지 올바른 방법이있는 이유는 무엇이며 어떤 상황에서 선호하는 것이 있습니까?

기본적 const으로 별표 이전의 지정자 내 위치가 중요하지 않은 이유는 C 문법이 Kernighan과 Ritchie에 의해 정의 되었기 때문입니다.

그들이 문법을 이런 식으로 정의한 이유는 C 컴파일러가 왼쪽에서 오른쪽으로 입력을 구문 분석하고 소비했을 때 각 토큰 처리를 완료했기 때문일 수 있습니다. *토큰을 소비하면 현재 선언의 상태가 포인터 유형으로 변경됩니다. 발생 const*수단 const규정 포인터 선언에인가되고; *한정자가 가리키는 데이터에 적용됨을 의미 하기 전에이를 발견했습니다 .

const한정자가 형식 지정자 앞이나 뒤에 나타나면 의미 론적 의미가 변경되지 않기 때문에 어떤 식 으로든 허용됩니다.

함수 포인터를 선언 할 때 비슷한 경우가 발생합니다.

  • void * function1(void)를 반환하는 함수를 선언합니다 void *.

  • void (* function2)(void)를 반환하는 함수에 대한 함수 포인터 를 선언 합니다 void.

다시 한 번 주목할 것은 언어 구문이 왼쪽에서 오른쪽으로 파서를 지원한다는 것입니다.


7
Kernighan은이 책을 공동 저술했지만 C의 디자인에는 관여하지 않았으며 Ritchie 만있었습니다.
Tom Zych

8
나는 어느 것이 어느 것인지 기억할 수 없었다. 귀하의 설명 덕분에 나는 그것을 기억하기 위해 mnemotechnic을 마침내 얻었습니다. 감사! *컴파일러 파서가 포인터인지 알기 전에 데이터 값의 구성 요소입니다. * 이후에는 상수 포인터와 관련이 있습니다. 훌륭한. 내가 할 수있는 이유 마침내는 설명 const char뿐만 아니라 char const.
Vit Bernatik

2
왜 이런 식으로 이루어 졌는지에 대한 추측은 나에게 다소 약하거나 자기 모순적 인 것처럼 보입니다. 즉, 언어를 정의하고 컴파일러를 작성하는 경우 언어를 간단하게 유지하고 "왼쪽에서 오른쪽으로 입력을 구문 분석하고 각 토큰을 사용할 때 처리를 마치고 싶다"고 말했듯이 나는 const항상 자격을 갖춘 것을 따라야합니다 ... 정확히 그것을 소비 한 직후 항상 const 처리를 마칠 수 있습니다. 따라서 이것은 서독을 허용하는 것이 아니라 금지 하는 주장으로 보입니다 .
돈 해치

3
"유형 한정자 앞뒤에 const 한정자가 나타나면 의미 론적 의미가 변경되지 않기 때문에 어떤 식 으로든 허용됩니다." 순환 추론 아닌가요? 질문 의 의미 적 의미 가 그렇게 정의되어 있는지에 대한 질문 이므로이 문장이 아무 것도 기여하지 않는다고 생각합니다.
돈 해치

1
@donhatch 당신은 오늘날과 비교할 때, 그리고 좋은 프로그래밍 언어 디자인에 대한 우리의 친숙함에 기초하여 가정을했을 때, 언어는 그 당시에는 아주 새로운 것들이었습니다. 또한 관용어 또는 제한 어가 있는지 여부는 가치 판단입니다. 예를 들어, 파이썬에는 ++연산자 가 있어야 합니까? 이호 (imho)“문장”은 그들이 할 수있는 것 이외의 특별한 이유가 없다는 것을 깨닫게 해주었다. 어쩌면 그들은 오늘 다른 선택을 할 수도 있고 아닐 수도 있습니다.
ragerdl

75

규칙은 다음과 같습니다.

const는 남은 것에 적용됩니다. 왼쪽에 아무것도 없으면 오른쪽에 적용됩니다.

const가 정의 된 "원래"방식이기 때문에 const 오른쪽에 const를 사용하는 것이 좋습니다.

그러나 저는 이것이 매우 주관적인 관점이라고 생각합니다.


18
나는 왼쪽에 두는 것을 선호하지만 오른쪽에 두는 것이 더 합리적이라고 생각합니다. 일반적으로 C ++에서 형식을 오른쪽에서 왼쪽으로 읽습니다. 예를 들어 Object const *const 객체에 대한 포인터입니다. 를 const왼쪽에두면 const 인 Object에 대한 포인터로 읽히지 만 실제로는 잘 흐르지 않습니다.
Collin Dauphinee

1
나는 왼쪽에 다른 종류의 C 선언과 인간 스타일의 일관성이 있다는 인상을 받고 있습니다 (컴퓨터 측면에서는 const스토리지 클래스가 아니기 때문에 정확 하지 않지만 사람들은 파서가 아닙니다).
geekosaur

1
@Heath 나는 그것이 규칙보다 지침이라고 생각하며 컴파일러가 그것을 해석하는 방법을 기억하는 방법으로 자주 들었습니다 ... 어떻게 작동하는지 이해합니다. 두 가지 방법 모두를 지원하기로 결정했습니다.
AJG85

3
@HeathHunnicutt 규칙이 존재하지만 조금 더 복잡합니다. c-faq.com/decl/spiral.anderson.html
imallett

2
@HeathHunnicutt : 나선 규칙은 첫 번째 주석 작성자의 주석 "확장 된 버전입니다."일반적으로 [C /] C ++에서 유형을 오른쪽에서 왼쪽으로 읽습니다 ". 나는 당신이 이것과 모순된다고 생각했습니다. 그러나 나는 당신이 대신 대답 자체를 언급하고 있다고 생각합니다.
imallett

57

나는 두 번째 구문을 선호합니다. 형식 선언을 오른쪽에서 왼쪽으로 읽어서 '무엇이 일정한지'추적하는 데 도움이됩니다.

Object * const obj;        // read right-to-left:  const pointer to Object
Object const * obj;        // read right-to-left:  pointer to const Object
Object const * const obj;  // read right-to-left:  const pointer to const Object

3
바로 그거죠. "상수 객체에 대한 상수 포인터"는 Object const* const아닙니다 const const Object*. 많은 사람들이 절대적으로 그것을 좋아하는 특별한 경우를 제외하고는 "const"는 왼쪽에있을 수 없습니다. (위의 Heath 참조)
cdunn2001

38

선언에서 키워드의 순서는 모두 고정 된 것은 아닙니다. "하나의 진정한 질서"에 대한 많은 대안이 있습니다. 이렇게

int long const long unsigned volatile i = 0;

아니면

volatile unsigned long long int const i = 0;

??


25
단순 변수의 완전히 혼동되는 정의는 +1입니다. :)
Xeo

@rubenvb-예, 불행히도 그들은 있습니다. 문법은 단지 a decl-specifier-seqdecl-specifiers 의 시퀀스 라고 말합니다 . 문법으로 주어진 순서는 없으며, 각 키워드에 대한 발생 횟수는 일부 의미 적 규칙에 의해서만 제한됩니다 (하나만 const두 개를 가질 수 있음 long:-)
Bo Persson

3
@rubenvb-예, 와 unsigned같은 유형 입니다. 다른 타입과 동일 하고 . 패턴을 보시겠습니까? unsigned intint unsignedunsigned longunsigned long intint long unsigned
보 Persson

2
@Bo : 난장판을보고, 패턴을 보려면 세 개가 있어야 ;)합니다. 감사합니다
rubenvb

1
예전 static에는 혼란스러워하는 단어 를 추가 할 수 있었지만 최근에는 컴파일러 static가 먼저 불평 해야한다고 불평했습니다 .
Mark Lakata 2016 년

8

첫 번째 규칙은 로컬 코딩 표준에 필요한 형식을 사용하는 것입니다. 그 후 : consttypedef가 관련되어있을 때 앞에 배치하면 혼란의 끝이 없습니다.

typedef int* IntPtr;
const IntPtr p1;   // same as int* const p1;

코딩 표준이 typedef의 포인터 포인터를 허용하는 경우 실제로 const를 형식 뒤에 두어야합니다. 모든 경우에 유형에 적용될 때 const는 적용되는 내용을 따라야하므로 일관성은 또한 const에 찬성하여 주장합니다. 그러나 지역 코딩 지침은이 모든 것을 능가합니다. 차이점은 일반적으로 돌아가서 기존 코드를 모두 변경하기에 충분하지 않습니다.


이 점에서 우리가 정의 하지 않은 표준에 포인터 타입 정의 가없는 이유를 강조 할 수 있다고 생각합니다 .
AJG85

1
내 정책 (혼자서 결정할 때)은 const를 뒤에 (일관성을 위해) 넣고 typedef를 포인터 (또는 일반적으로 typedef를 많이 사용하지 않는) :-)하지 않는 것입니다. 그리고 BTW, string :: iterator vs. string :: const_iterator는 아마도 귀하의 결정에 반영되어야합니다. (혼란을 혼동시키기 만하면됩니다 :-). 정답은 없습니다.)
James Kanze

아 그래, 나는 const std::string::const_iterator좋은 측정을 위해 행동을 포함시킬 수 있었다 ;)
AJG85

2
@JamesKanze — 잠깐만 기다려주세요. 게시 된 예제에서 혼란을 보지 못했습니다. const IntPtr p1"일정한 정수 포인터"이외의 다른 의미 는 무엇입니까 (즉, "정수에 대한 상수 포인터")? IntPtr정의 된 방법을 알지 못하더라도 올바른 생각을 가진 사람은 아무도 그것을 p1바꿀 수 없다고 생각할 것입니다 . 그리고 그 문제에 대해 왜 아무도 *p1불변 이라고 잘못 생각 합니까? 더구나 const를 다른 곳에 (예를 들어 IntPtr const p1) 두는 것은 의미를 전혀 바꾸지 않습니다.
Todd Lehman 1

3
@ToddLehman 혼란을 볼 수는 없지만 대부분의 C ++ 프로그래머는 체계적으로 잘못 이해합니다 std::vector<T>::const_iterator.
James Kanze

7

왼쪽 또는 오른쪽이 허용되는 역사적인 이유가 있습니다. Stroustrup은 1983 년까지 C ++에 const를 추가 했지만 C89 / C90까지는 C로 만들지 않았습니다.

C ++에서는 항상 const를 오른쪽에 사용해야하는 좋은 이유가 있습니다. const 멤버 함수 는 다음과 같이 선언 해야 하므로 어디에서나 일관성 이 있습니다.

int getInt() const;

1
"좋은 이유"는 그다지 설득력이 없습니다. "const"의 다른 가능한 위치는 같은 것을 의미하지 않기 때문입니다. const int& getInt(); int& const getInt();
Maestro

1
@Maestro : 나는 제안하고는 int const& getInt();더 동등보다 const int& getInt();반면 int& const getInt();당신과 비교하는 것이 중복하지만 법률 (참조가 const를 이미) 일반적으로 경고를 줄 것이다. 어쨌든, 멤버 함수 const를이 변경 this에서 함수의 포인터 Foo* const로를 Foo const* const.
Nick Westgate

const멤버 함수에서 똑같은 의미가 아니거나 void set(int)&;함수에 대한 일종의 참조입니까?
Davis Herring
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.