2010. 4. 3. 11:55

포인터 문법에 관한 고찰

아래의 문법은 컴파일하여도 전혀 문제가 되지 않습니다.

-----------------------------------------

int array[10];

int *ptr = array;

-----------------------------------------

2번째 라인을 int *ptr = &array;로 바꾸어 컴파일하면 에러가 발생합니다.

array는 포인터 상수로, &array와 같은 주소값을 가짐에도 불구하고 말입니다.


이유가 무엇일까요?

아주 예전에 제가 위의 문제로 고민을 한적이 있었습니다. 하하.

우리가 생각한대로 int *ptr = &array가 되어야 합리적으로 보여질 수 있습니다.

하지만 다음과 같은 에러를 출력하는 것을 보실 수 있습니다.

'initializing' : cannot convert from 'int (*)[10]' to 'int *'

참 이상하죠? 배열명 array 자체는 주소값을 의미하고 거기에 단지 &연산을 했을 뿐인데 말입니다.

독자는 분명히 array == &array 라는 사실을 의심치 않을 겁니다.

왜냐하면, printf( "%x", array  ); 와

            printf( "%x", &array ); 이 같고,

            printf( "%d", sizeof(array)  ); 와

            printf( "%d", sizeof(&array) ); 가 같은데 말이죠.

 즉, 대상체가 의미하는 주소값과 대상체의 크기는 모두 동일하다는 것입니다.

그럼 다시 위의 에러를 살펴 봅시다.

[배열 포인터]형을 [포인터]형으로 변환이 불가능하다는 의미가 될 겁니다.

그래서 다시, int (*ptr)[10] = &array; 해서 컴파일 해 보았습니다.

에러없이 컴파일이 잘 되는군요. 하지만 상식적으로 저 역시 이해가 되질 않습니다.

여전히 의문을 가질 수 밖에 없었습니다. 그렇다면 좀 더 시각을 달리해보는건 어떨까

합니다. 배열명 array는 우리가 알고 있는대로 [포인터 상수]입니다.

배열명 자체가 주소값을 의미합니다. 그렇다면 상수에 &연산이 가능하다는 것조차도

논리적으로 좀 이상하지  않겠습니까?

&연산은 변수의 선두 번지를 구하는 연산이라는 것을 독자들도 잘 아실 겁니다.

그렇지만 &연산은 가능합니다. 왜냐하면, printf( "%d", &array );가 무리없이 컴파일되니까

말입니다. 저는 사실 이것도 뭔가 찝찝하다고 생각하였는데 독자가 동의하실지 모르겠습니다.

상수에 &연산을 허용한다는 것은 결국 &(&array)도 허용해야 하지 않겠습니까?

하지만 이것은 컴파일 에러를 출력합니다. '&' requires l-value로 말이죠.

(VC++로 컴파일하였을 때 기준)

하지만 다른 여러 컴파일러에서는 int *ptr = &array;가 허용되는 것으로 알고 있습니다.
(리눅스의 gcc가 허용하는 것으로 알고 있습니다)

우리들이 의도하신대로 말이죠. 제가 말하고 싶은 결론은 컴파일러의 Dependent한 문제라고

볼 수 밖에 없습니다. 항상 우리가 생각하는 논리와 의도대로 모든 문법이 구성이 되어있지 않

습니다. 저 역시 이 부분은 개인적으로 굉장히 아쉬운 부분으로 생각하고 있습니다.

결국은 컴파일러 문제죠. 여기까지는 컴파일러가 정한 문법 규칙이라고 밖에 볼 수 없습니다.

제가 그렇게 확신하는 이유가 다음의 Disassembling 코드때문입니다.

 

9:        printf( "%d\n", array  );

0040D76B   lea           eax,[ebp-28h]
0040D76E   push        eax
0040D76F   push        offset string "%d" (0042201c)
0040D774   call          printf (0040d6c0)
0040D779   add          esp,8 

10:       printf( "%d\n", &array );

0040D77C   lea          ecx,[ebp-28h]
0040D77F   push        ecx
0040D780   push        offset string "%d" (0042201c)
0040D785   call          printf (0040d6c0)
0040D78A   add         esp,8

 
같은 Addressing Mode로 연산을 한다는 사실을 위의 코드로 증명하였습니다.

( [확장자 .c]로 하여 int *ptr = &array; 컴파일하면 에러는 나지 않고 경고만 출력하더군요. )

컴파일러에 의해서 어쩔수 없는 부분은 그려려니 인정하고 이해보다는 암기하여

사용할 수 밖에 없다는 것이라고 생각합니다.

Written By Sim-Hyeon, Choe