2011-02-16 1 views
2

C/C++에서 "포인터를 쓰는"좋은 방법이 있습니까?
void foo(char *str);을 쓰는 데 사용하지만 str의 형식이 "char to pointer"이기 때문에 때로는 상당히 비논리적입니다. *을 형식 이름에 연결하는 것이 더 논리 적이어야합니다.
포인터를 쓰는 규칙이 있습니까?C/C++에서 "포인터를 쓰는"좋은 방법

char*str; 
char* str; 
char *str; 
char * str; 
+1

C 또는 C++ 사용자입니까? 대답은 완전히 다릅니다. – Puppy

+2

'void foo (pointer_to_char str);':) –

+0

왜'std :: string'이 아니겠습니까? 또는'const char *', 적어도. – GManNickG

답변

9

공통 C 규칙은 을 작성하는 반면 공통 C++ 규칙은 T* p을 작성하는 것입니다. 두 구문 모두 T (*p); *은 형식 지정자가 아닌 선언 자의 일부입니다. 이것은 순전히 포인터 선언 구문의 우연한 사고입니다. 어느 쪽이든 작성할 수 있습니다.

C (및 확장, C++) 선언 구문은 표현 중심입니다. IOW, 선언의 형식은 코드에서 같은 유형의 표현식의 형식과 일치해야합니다.

예를 들어, int에 대한 포인터가 있고 그 정수 값에 액세스하려고한다고 가정합니다. 이렇게하려면, 우리가 지금처럼 역 참조 * 간접 연산자와 포인터를 :

x = *p; 

*pint표현의 유형; 따라서, p의 INT 다움이 타입 지시자 int 의해 제공되지만 p의 포인터 네스가 선언자 *p 의해 제공

int *p 

p 선언 될 것을 따른다.

약간 더 복잡한 예로, float의 배열에 대한 포인터가 있다고 가정하고 포인터를 통해 배열의 i 번째 요소에서 부동 소수점 값에 액세스하려고한다고 가정합니다. 배열 포인터 역 참조 우리와는 결과를 첨자 :

f = (*ap)[i]; 

(*ap)[i]float표현의 유형, 배열 포인터의 선언이

float (*ap)[N]; 

플로트 네스 것을 다음 있도록 ap은 형식 지정자 float에 의해 제공되지만 포인터 모양과 배열 모양은 선언자 (*ap)[N]에 의해 제공됩니다. 이 경우 *이어야하며 명시 적으로은 식별자에 바인딩되어야합니다. []은 표현식과 선언 구문 모두에서 단 하나의 *보다 높은 우선 순위를 가지므로 "float에 대한 포인터"보다는 "이 아닌 float"에 대한 포인터의 배열 인 으로 구문 분석됩니다. 난 당신이 하지만

float(* ap)[N]; 

나는이 점은 어떻게 될지 모르겠어요 것을 쓸 수도있을 것 같군요; ap의 유형을 더 명확하게하지는 않습니다.

더 좋은 방법 int 포인터의 배열에 대한 포인터를 반환하는 함수에 대한 포인터에 대한 : 다시

int *(*(*f)())[N]; 

* 사업자의 이상이 명시 적으로 선언자에 결합되어야한다

int* (*(*f)())[N]; 

같이 형식 지정자에 마지막 * 바인딩 단지 IMO 혼란의 생각을 나타냅니다. 나는 그것이 인기가 왜 이해에도 불구하고, 내 자신의 C++ 코드에서 사용하더라도

, 나는이 T* p 규칙 뒤에 추론으로 가지고있는 문제는 단지 간단한의 외부에는 적용되지 않는다는 것입니다 C 및 C++ 선언 구문에 대한 단순한 관점에서 잘못된 관점을 보완합니다. 예, p의 형식은 "T에 대한 포인터"이지만 언어 문법에 관한 한 *은 형식 지정자가 아닌 선언자에 바인딩된다는 사실을 변경하지 않습니다. a의 유형은 "T의 N-요소 배열"의 경우 다른 경우를 들어

, 우리는 문법을 허용하지 않습니다, 분명히하지
쓰기를

T[N] a; 

. 이 경우에도 인수는을 적용하지 않습니다.

편집 스티브 코멘트에서 지적 하듯이

, 당신은 복잡성의 일부를 숨길 형식 정의를 사용할 수 있습니다. 예를 들어, arrptrfunc* ff를 선언, 당신은 깨끗하게 T* p 규칙을 적용 할 수 있습니다 지금

typedef int *iptrarr[N];   // iptrarr is an array of pointer to int 
typedef iptrarr *arrptrfunc();  // arrptrfunc is a function returning 
            // a pointer to iptrarr 

arrptrfunc *f;      // f is a pointer to arrptrfunc 

같은 것을 같은

int *(*(*f)())[N]; 

를 다시 작성할 수 있습니다. 저는 개인적으로 이런 식으로 일하는 것을 좋아하지 않습니다. 왜냐하면 typedef에서 표현식에 f이 어떻게 사용되어 지는지 또는 arrptrfunc 유형의 객체를 사용하는 방법이 반드시 명확하지 않기 때문입니다. non-typedef 버전은보기 흉하고 읽기가 어려울 수 있지만 최소한 앞에서 알아야 할 모든 것을 알려줍니다. 당신은 모든 typedef를 파헤 치지 않아도됩니다.

+0

"int * (* (* f)()) [N];'혼란스러운 사고 IMO를 나타냅니다." - 똑바로. 기본 가독성을 위해, 몇 가지 typedef를 사용하십시오 :-) –

+3

@ 스티브 : 아,하지만 typedef는 자신의 문제를 소개합니다. 'int * (* (* f)()) [N];'은 읽을 수없는 부분에 국경을 둘 수 있지만 적어도 식으로'f'를 사용하는 방법을 한 눈에 알 수 있습니다. 'Fptr f'와 같은 typedef에 숨겨져 있다면, 제대로 사용하는 법을 알기 위해서는 정의를 파헤쳐 야합니다. 나는이 점에서 나는 이상한 사람이라는 것을 알고 있지만, 나는 그 이유 때문에 non-typedef 된 버전을 선호한다. 그리고 typedef 뒤에 포인터를 숨기는 것은 항상 나를 위해 가슴 앓이로 이어지는 것으로 보인다. –

21

그래서 * 변수에 연결을 염두에두고 엄격한 규칙, 그러나 곰은 없다 :

char *str1, *str2; // str1 and str2 are pointers 
char* str1, str2; // str1 is a pointer, str2 is a char 

어떤 사람들뿐만 아니라 char * str1을 좋아하지만, 당신이 나에게 달려 당신의 회사의 코딩 표준.

+0

아주 좋은 예입니다. – Benoit

+5

많은 지침에 따라 변수 이름에'*'를 붙이는 것이 좋습니다. 그러나 더 나은 방법은 같은 줄에 여러 변수를 선언하는 것을 피하는 것입니다.보다 명확하고 유지 관리가 쉬우 며 오류가 발생하기 쉽지 않습니다. 그리고이 경우,'*'의 위치는 거의 중요하지 않습니다. (개인적으로, 전후에 공백을 넣으므로 포인터 (또는 참조)를 찾기가 더 쉬워 지지만 대부분 맛이 있습니다). –

+0

'*'가 당신이 살았던 곳보다 오랫동안 붙어있는 곳을 사람들이 논한다는 것을 명심하십시오. –

3

은 "좋은 방법은"프로젝트에

  1. 내부 코딩 표준에
  2. 귀하의 개인 환경 설정

(아마)의 순으로을 따라 달라집니다.

+0

"더 좋은 방법"은 "더 논리적 인 또는 자연스러운 길"이라고 생각합니다 –

+1

@Soubok : 여전히 작동합니다. 보다 논리적이고 자연스러운 방법은 프로젝트 표준과 개인 취향에 달려 있습니다. 그것은 가독성과 미학의 주관적인 문제입니다. 자신의 선호가 "정확하다"는 것을 "증명"하기 위해 그렇지 않으면 그것을 만드는 것을 시도하는 사람들은 도둑과 겁쟁이입니다. –

0

이것이 변수를 선언하는 일반적인 패턴에 크게 영향을받을 것이라고 생각합니다.

예를 들어, 한 줄에 하나의 변수 만 선언하는 경향이 있습니다. 이렇게하면 변수를 어떻게 사용할지 알려주는 설명을 추가 할 수 있습니다.

그러나 동일한 유형의 여러 변수를 한 줄에 선언하는 것이 실용적인 경우가 있습니다. 이러한 상황에서 필자의 개인 코딩 규칙은 결코 포인터와 같은 줄에 포인터를 선언하지 않습니다. 나는 그것들을 믹싱하는 것이 에러의 원천이 될 수 있다는 것을 알기 때문에 믹싱을 피함으로써 "잘못된 것"을보다 쉽게 ​​볼 수 있도록 노력한다.

첫 번째 지침을 따르는 한 일관성이있는 한 포인터를 어떻게 선언 하느냐가 과도하게 중요하지 않습니다.. 내가 두 번째 가이드 라인을 사용하고 같은 줄에 여러 포인터를 선언하는 경우

그러나, 나는

char *ptr1, *ptr2, *ptr3; 

으로 ... 다음 스타일이 가장 유익하고 (물론 다른 사람들이 동의하지 않을 수 있습니다) 명확하게 찾을 *와 포인터 이름 사이에 공백이 없으면 두 번째 지침을 위반했는지 여부를 쉽게 알 수 있습니다. 이제

내 두 개인 스타일 가이드 라인과 일치하기를 원한다면 라인에 하나의 포인터를 선언 할 때, 내가 사용하는 것이

... 어쨌든
char *ptr; 

는, 그 이유의 일부에 대한 내 근거이다 나는 내가하는 일을한다. 희망이 도움이됩니다.

+1

몇 가지 변수를 한 줄에 선언하는 것이 왜 실용적인가? 이 난독 화 된 구문의 원래 이유는 C가 HD 공간이 매우 가치있는 시점에 설계 되었기 때문에 소스 코드 파일 자체를 작게 유지해야한다는 것입니다. 한 줄에 여러 변수를 선언하는 이유는 다음과 같습니다. 1) 70 년대의 HD로 컴퓨터 프로그래밍, 2) 게으름, 3) 난해한 C 코딩 경연 대회, 4) 마모 감소 5) 소스 코드가 기계어 코드로 변환되는 방법에 대한 지식이 부족합니다. – Lundin

+0

요점은 첫 번째 지침을 깨거나 구부릴 필요가 있다고 생각되면 가능한 한 안전하고 사려 깊게 시도하십시오. 왜 그것을 끊을까요? 주된 이유는 (또는 원하는 경우 변명) 인식 할 수있는 가독성입니다. 한 줄에 하나의 변수를 선언하면 많은 화면 공간을 씹을 가능성이 있습니다. 또는 다소 고안된 예제를 원한다면 각각의 인덱스/카운터가있는 N 레벨의 깊이가있는 중첩 루프를 고려하십시오. N 개의 변수에 N 개의 변수를 넣는 대신에 "loop variable"이라고하는 주석을 달아서 모두 같은 주석으로 한 줄에 넣으십시오. – Sparky

1

여기에는 옳고 그름이 없습니다. 중요한 것은 하나의 코딩 표준을 선택하고이를 준수하는 것입니다.

필자는 개인적으로 유형이 "char to pointer"이기 때문에 변수 이름이 아니라 유형에 속한다고 믿습니다. 변수 이름은 포인터가 아닙니다.