포인터 선언에 별표 배치


92

나는 최근에 마침내 C / C ++를 배워야한다고 결정했고, 포인터에 대해 정말로 이해하지 못하는 것이 한 가지 있습니다. 더 정확하게는 그 정의입니다.

이 예는 어떻습니까?

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

이제 내 이해에 따르면 처음 세 가지 경우는 모두 동일합니다. Test는 int가 아니라 1에 대한 포인터입니다.

두 번째 예제 세트는 좀 더 까다 롭습니다. 경우 4에서 test와 test2는 모두 int에 대한 포인터가되고, 경우 5에서는 test 만 포인터이고 test2는 "실제"int입니다. 사례 6은 어떻습니까? 사례 5와 같습니까?


10
C / C ++에서 공백은 의미를 변경하지 않습니다.
Sulthan

19
7. int*test;?
Jin Kwon

3
1-3에 대해서만 물어볼 생각 이었기 때문에 +1했습니다.이 질문을 읽으면서 생각하지 못했던 4-6에 대한 정보를 얻었습니다.
hugelysuperiorman

@Sulthan 그것은 99 %의 경우 사실이지만 항상 그런 것은 아닙니다. 내 머리 꼭대기에는 템플릿 유형 공간 요구 사항 (C ++ 11 이전)에 템플릿 유형 유형이있었습니다. 에서 기록했다 않도록 오른쪽 교대로 취급하지. Foo<Bar<char>>>>> >
AnorZaken

3
@AnorZaken 당신이 맞습니다, 그것은 다소 오래된 코멘트입니다. 공백이 의미를 변경하는 여러 상황이 있습니다. 예를 들어 증분 ++연산자를 공백으로 분할 할 수없고 식별자를 공백으로 분할 할 수 없습니다 (그리고 결과는 컴파일러에 대해 여전히 합법적이지만 정의되지 않은 런타임 동작이있을 수 있음). 정확한 상황은 C / C ++의 문법 혼란을 고려하면 정의하기 매우 어렵습니다.
Sulthan

답변:


129

4, 5, 6은 동일하며 테스트 만 포인터입니다. 두 개의 포인터를 원하면 다음을 사용해야합니다.

int *test, *test2;

또는 더 나은 (모든 것을 명확하게하기 위해) :

int* test;
int* test2;

3
그렇다면 사례 4는 실제로 죽음의 함정입니까? int * test, test2가 첫 번째 변수 만 포인터로 만드는 이유를 설명하는 사양이나 추가 자료가 있습니까?
Michael Stum

8
@ Michael Stum C ++인데 정말 논리적 설명이 있다고 생각하십니까?
Joe Phillips

6
K & R (The C Programming Language)을 읽으십시오. 이 모든 것을 매우 명확하게 설명합니다.
Ferruccio

8
사례 4, 5 및 6은 "죽음의 함정"입니다. 이것이 많은 C / C ++ 스타일 가이드가 명령문 당 하나의 선언 만 제안하는 이유 중 하나입니다.
Michael Burr

14
공백은 C 컴파일러에서 중요하지 않습니다 (전 처리기 무시). 따라서 별표와 그 주변 사이에 몇 개의 공백이 있든 없든 정확히 같은 의미를 갖습니다.
ephemient

45

별표 주위의 공백은 의미가 없습니다. 세 가지 모두 같은 의미입니다.

int* test;
int *test;
int * test;

" int *var1, var2"는 사람들을 혼란스럽게하기위한 사악한 구문이므로 피해야합니다. 다음으로 확장됩니다.

int *var1;
int var2;

16
잊지 마세요 int*test.
Mateen Ulhaq

1
별표 앞뒤의 공간은 미학의 문제 일뿐입니다. 그러나 Google Coding 표준은 int *test( google-styleguide.googlecode.com/svn/trunk/… ) 와 함께 사용 됩니다. 일관성을 유지

@SebastianRaschka Google C ++ 스타일 가이드 에서는 별표 배치를 명시 적으로 허용합니다. 읽은 이후로 변경되었을 수 있습니다.
Jared Beck

33

많은 코딩 지침 은 한 줄에 하나의 변수 만 선언하도록 권장합니다 . 이렇게하면이 질문을하기 전에 가졌던 종류의 혼동을 피할 수 있습니다. 내가 함께 일한 대부분의 C ++ 프로그래머는 이것에 집착하는 것 같습니다.


내가 아는 약간의 제쳐두고 유용한 것은 선언을 거꾸로 읽는 것입니다.

int* test;   // test is a pointer to an int

이것은 매우 잘 작동하기 시작합니다. 특히 여러분이 const 포인터를 선언하기 시작할 때 그것이 const 인 포인터인지 아니면 포인터가 가리키는 것이 const인지를 아는 것이 까다로워집니다.

int* const test; // test is a const pointer to an int

int const * test; // test is a pointer to a const int ... but many people write this as  
const int * test; // test is a pointer to an int that's const

"한 줄에 하나의 변수"가 유용 해 보이지만 별표가 왼쪽에 더 많거나 오른쪽에 더 많은 상황을 완전히 해결하지는 못했습니다. 나는 야생의 코드에서 하나의 변종이 우세하다고 확신합니다. 일부 국가는 오른쪽으로 운전하고 다른 국가는 영국과 같이 잘못된 방향으로 운전하는 것과 비슷합니다. ;-)
shevy

불행히도 내 모험에서 야생으로 나는 두 가지 스타일을 많이 볼 수 있습니다. 우리 팀에서는 이제 합의한 스타일로 clang-format을 사용합니다. 이것은 적어도 우리 팀이 생성하는 모든 코드가 공백이가는 위치에 대해 동일한 스타일을 가지고 있음을 의미합니다.
Scott Langham

33

"Clockwise Spiral Rule" 을 사용하면 C / C ++ 선언을 구문 분석하는 데 도움이됩니다.

따라야 할 간단한 세 단계가 있습니다.

  1. 알 수없는 요소부터 시작하여 나선 / 시계 방향으로 이동합니다. 다음 요소가 발견되면 해당 영어 문으로 대체하십시오.

    [X]또는 []: 배열 X 크기 ... 또는 배열 정의되지 않은 크기 ...

    (type1, type2): 함수 전달 type1 및 type2 반환 ...

    *: 포인터 ...

  2. 모든 토큰이 덮일 때까지 나선형 / 시계 방향으로 계속하십시오.
  3. 항상 괄호 안의 모든 것을 먼저 해결하십시오!

또한 선언은 가능한 경우 별도의 문으로 작성해야합니다 (대부분의 경우 사실임).


4
그것은 벅차고 매우 끔찍해 보입니다. 죄송합니다.
Joe Phillips

7
그렇습니다,하지만 더 복잡한 구조의 일부에 대한 아주 좋은 설명을 보인다
마이클 방부제로 발효를 막다

@ d03boy : 의심 할 여지가 없습니다. C / C ++ 선언은 악몽이 될 수 있습니다.
Michael Burr

2
"나선형"은 의미가 없으며 "시계 방향"보다 훨씬 적습니다. 구문이 오른쪽 하단 왼쪽 상단이 아니라 오른쪽 왼쪽 만 보이게하기 때문에 차라리 "오른쪽-왼쪽 규칙"이라고 명명합니다.
Ruslan

저는 이것을 "오른쪽-왼쪽-오른쪽"규칙으로 배웠습니다. C ++ 사용자는 모든 유형 정보가 왼쪽에있는 것처럼 가장하기를 좋아하는데, 이는 int* x;전통적인 int *x;스타일이 아닌 스타일로 이어집니다 . 물론, 간격은 컴파일러에게는 중요하지 않지만 사람에게는 영향을줍니다. 실제 구문을 거부하면 독자를 괴롭 히고 혼란스럽게 할 수있는 스타일 규칙이 생깁니다.
Adrian McCarthy

12

다른 사람들이 언급했듯이 4, 5 및 6은 동일합니다. 종종 사람들은이 예제를 사용 *하여 유형이 아닌 변수에 속하는 인수를 만듭니다 . 스타일의 문제이긴하지만 이렇게 생각하고 작성해야하는지에 대한 논쟁이 있습니다.

int* x; // "x is a pointer to int"

또는 이렇게 :

int *x; // "*x is an int"

FWIW 나는 첫 번째 캠프에 있지만 다른 사람들이 두 번째 형식에 대해 주장하는 이유는 (대부분)이 특정 문제를 해결하기 때문입니다.

int* x,y; // "x is a pointer to int, y is an int"

잠재적으로 오해의 소지가 있습니다. 대신 당신은

int *x,y; // it's a little clearer what is going on here

또는 정말로 두 개의 포인터를 원한다면

int *x, *y; // two pointers

개인적으로 한 줄에 하나의 변수로 유지하면 어떤 스타일을 선호하는지는 중요하지 않습니다.


6
이것은 가짜입니다. 뭐라고 부르 int *MyFunc(void)나요? a *MyFunc를 반환하는 함수 int입니까? 아니. 분명히 우리는 작성해야 int* MyFunc(void)하고, 말은 MyFunc를 반환하는 기능입니다 int*. 그래서 나에게 이것은 분명합니다. C 및 C ++ 문법 구문 분석 규칙은 변수 선언에 대해 잘못되었습니다. 전체 쉼표 시퀀스에 대한 공유 유형의 일부로 포인터 제한을 포함해야합니다.
v.oddou

1
그러나 *MyFunc() 입니다int . C 구문의 문제는 접두사접미사 구문을 혼합 하는 것입니다. 접미사 사용하면 혼동이 없습니다.
Antti Haapala

1
첫 번째 캠프는 같은 혼란 구조로 이어지는 언어의 구문을 싸움 int const* x;나는대로 오해의 소지로 발견 a * x+b * y.
Adrian McCarthy


5

4, 5 및 6에서 test항상 포인터이며 포인터 test2가 아닙니다. 공백은 C ++에서 거의 중요하지 않습니다.


3

제 생각에는 상황에 따라 대답은 둘 다입니다. 일반적으로 IMO에서는 유형이 아닌 포인터 이름 옆에 별표를 두는 것이 좋습니다. 예를 들어 비교 :

int *pointer1, *pointer2; // Fully consistent, two pointers
int* pointer1, pointer2;  // Inconsistent -- because only the first one is a pointer, the second one is an int variable
// The second case is unexpected, and thus prone to errors

두 번째 경우가 일치하지 않는 이유는 무엇입니까? eg int x,y;는 동일한 유형의 두 변수를 선언하지만 유형은 선언에서 한 번만 언급되기 때문입니다. 이것은 선례적이고 예상되는 행동을 만듭니다. 그리고 int* pointer1, pointer2;이 선언 때문에 그와 일관성이없는 pointer1포인터로하지만,pointer2 정수 변수입니다. 오류가 발생하기 쉬우므로 피해야합니다 (유형이 아닌 포인터 이름 옆에 별표를 표시).

그러나 원치 않는 결과를 얻지 않고는 객체 이름 옆에 별표를 넣을 수없는 경우 (그리고 어디에 넣는 것이 중요한지) 몇 가지 예외 가 있습니다. 예를 들면 다음과 같습니다.

MyClass *volatile MyObjName

void test (const char *const p) // const value pointed to by a const pointer

마지막으로, 어떤 경우 에는 유형 이름 옆에 별표를 두는 것이 더 명확 할 수 있습니다 . 예 :

void* ClassName::getItemPtr () {return &item;} // Clear at first sight


2

C의 이론적 근거는 변수를 사용하는 방식으로 선언한다는 것입니다. 예를 들면

char *a[100];

그 말한다 *a[42]될 것입니다 char. 그리고 a[42]char 포인터. 따라서a char 포인터의 배열입니다.

이는 원래 컴파일러 작성자가 표현식과 선언에 동일한 파서를 사용하기를 원했기 때문입니다. (언어 디자인 선택에 대한 그다지 합리적인 이유가 아님)


그러나 쓰기 char* a[100]; 는 또한*a[42]; a chara[42];char 포인터 가 될 것이라고 추론합니다 .
yyny

글쎄, 우리는 모두 같은 결론을 추론하고 순서 만 다릅니다.
Michel Billaud

인용구 : "* a [42]는 문자가되고 a [42]는 문자 포인터가된다고 말합니다." 그 반대가 아니라고 확신하십니까?
deLock

당신이 다른 방법을 선호하는 경우, 말은 a[42]A는 char포인터, 그리고 *a[42]숯불입니다.
Michel Billaud

2

나는 초기 규칙이 포인터 이름 쪽 (선언의 오른쪽)에 별을 두는 것이 었다고 말할 것입니다.

똑같은 규칙을 따를 수는 있지만, 타입쪽에 별표를 붙이면 큰 문제는 아닙니다. 일관성 이 중요하므로 어느 편을 선택하든 항상 같은 편에있는 별을 기억 하십시오.


글쎄요-파서가 두 변형을 허용하는 것처럼 보이지만 Dennis와 Linus가 그것이 오른쪽에 있어야한다고 말하면 꽤 설득력이 있습니다. 그러나 여전히 우리는 약간의 근거가 부족하고 이것이 왜 수행되는지 설명합니다. 탭이 아닌 스페이스를 사용하는 사람들이 더 많은 돈을 벌기 때문입니다. StackOverflow에 따르면 ... :-)
shevy

1

포인터는 유형에 대한 수정 자입니다. 별표가 유형을 수정하는 방법을 더 잘 이해하려면 오른쪽에서 왼쪽으로 읽는 것이 가장 좋습니다. 'int *'는 "int에 대한 포인터"로 읽을 수 있습니다. 여러 선언에서 각 변수가 포인터인지 아니면 표준 변수로 생성되는지 지정해야합니다.

1,2 및 3) 테스트 유형 (int *)입니다. 공백은 중요하지 않습니다.

4,5 및 6) 테스트 유형 (int *)입니다. Test2는 int 유형입니다. 다시 공백은 중요하지 않습니다.


-3

경험상 많은 사람들이 이러한 개념을 다음과 같이 이해하는 것 같습니다. C ++에서 많은 의미 론적 의미는 키워드 또는 식별자의 왼쪽 바인딩에 의해 파생됩니다.

예를 들어 :

int const bla;

const는 "int"단어에 적용됩니다. 포인터의 별표도 마찬가지이며 왼쪽 키워드에도 적용됩니다. 그리고 실제 변수 이름은? 네, 그것은 남은 것에 의해 선언되었습니다.


1
이것은 질문에 대한 답이 아닙니다. 더 나쁜 것은 우리 가 답 을 추론 하려고 하면 별표가 왼쪽에있는 유형에 묶여 있음을 의미하며 다른 모든 사람들이 말했듯이 거짓입니다. 오른쪽의 단일 변수 이름에 바인딩됩니다.
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.