김도완님이 먼저 선수를 쳐버리셨으니 김이 좀 빠져버렸습니다만..
이해를 잘 하기 힘드신 분들을 위해 풀어서 설명을 하자면 대략 다음과 같습니다.
이 문제에는 언어 기초적인 면에서 이해해야 할 두가지 개념적인 문제가 있습니다.
첫번째로, 오브젝트 파스칼에서 따옴표 두개 사이에 문자가 하나일 때는 문자열이 아니라 하나의 문자 상수로 취급되죠.
그래서 '1'은 문자열이 아니라 문자 상수 '1'이 전달됩니다.
이건 파스칼에서 1바이트 문자 상수와 문자열 상수의 표기법이 모두 한따옴표(single quotation)로 똑같기 때문에 생기는 문제입니다. (C/C++에서는 문자열 상수와 문자 상수의 표기법이 다르므로 이런 문제가 생기지 않죠.) 사실 컴파일러는 두가지를 명백하게 구별하는데, 개발자가 보통 구별하지 않기 때문에 여기에서 문제가 시작됩니다.
두번째 문제는, 함수 호출시에 PChar()로 캐스팅한 데에 있죠. 만약 이 '1' 값을 그냥 그대로 넘겼으면 아무 문제가 발생하지 않습니다. PChar형 인자에 문자 '1'을 넘기는 과정에서 문자 '1'이 스트링 '1'로 자동 캐스팅이 되죠.
그런데 나름대로 원칙에 충실하게 한다고 PChar로 강제 캐스팅을 하는 바람에, 문자열 '1'이 PChar로 캐스팅된 것이 아니라 문자 '1'이 PChar로 캐스팅되었죠. 문자 1은 31이라는 아스키값이기 때문에 이게 다시 포인터로 캐스팅되어버렸죠. 그래서 '1'이라는 문자열 대신 $31이라는 포인터가 전달되어버렸습니다.
사실, 원칙적으로 보자면 분명한 개발자의 실수이기 때문에 델파이 컴파일러를 탓할 것이 못됩니다만, 주정섭님께서 말씀하신 것처럼 개발자가 실수할 수 있는 부분이므로 warning 메시지를 내놓았으면 좋았겠다 싶군요.
이 문제를 피하려면... 제가 생각하기에 안전한 방법은, 역시 원칙적으로 해결하는 겁니다.
김도완님 말씀대로 1바이트 문자열 상수를 넘길 때 조심하는 것이 제일이겠지만, 이건 코딩 습관의 문제에 가깝기 때문에, 개발자의 머릿속에 1바이트인지 아닌지 잘 따져서 버그를 피하기가 쉽진 않겠죠. 습관적으로 익혀서 피해갈 수 있는 방법 두가지를 추천하자면...
1. PChar를 넘겨야 할 인자 위치에 문자열 상수를 넘길 때는 PChar로 강제 캐스팅을 하지 않는다.
ShellExecute(0, 'Open', PChar(ExeName), '1', nil, SW_SHOW);
2. 문자 변수를 PChar로 캐스팅하기 전에 먼저 string으로 캐스팅해준다.
ShellExecute(0, 'Open', PChar(ExeName), PChar(string('1')), nil, SW_SHOW);
전 간략한 1번 방법을 선호합니다. (단순무식 코딩 제일주의자~)
주정섭 님이 쓰신 글 :
: 지인이 요청하길, 도저히 실행 에러가 뜰수 없는 코드인데도 불구하고, 실행시 에러가 발생하기에, 그 원인을 분석해 달라고 했다. 아래는 지인이 준 소스 중에서, 그 유명한 엑세사리 바이올린이 떠는 소스 부분이다.
:
: var
: ExeName: String;
: begin
: // ShellExecute에서 호출할 외부 실행 파일명 얻기
: ExeName:= ExtractFilePath(ParamStr(0)) + 'Project2.exe';
:
: // 문제의 실행에러 라인
: ShellExecute(0, 'Open', PChar(ExeName), PChar('1'), nil, SW_SHOW);
: end;
:
: 이 프라젝트와 동일한 폴더에 Project2.exe가 존재하며, 이 실행 파일은 단독으로는 너무도 잘 실행된다. 다시말해서 Project2.exe는 아무런 문제도 없다는 것이다. Project2.exe는 델파이에서 새로운 프라젝트를 생성하면 기본으로 만들어지는 빈폼 하나 달랑있는 실행 파일일 뿐이다.
:
: 따라서, ShellExecute 실행 라인에서 Project2.exe는 원인이 아니다. 그렇다면 ShellExecute의 어떤 부분에서 에러가 발생한 것일까? 이 소스를 컴파일해보면 어떤 경고도 떨어지지 않는다. 그러나 실행시 엑세사리 바이올린이 연주를 하는 걸로 봐서는 분명히 뭔가 잘못된 부분이 있다. 즉 델파이 컴파일러조차도 감지 못했던 미묘한 버그가 있다는 것이다.
:
: 그 버그는 대체 무엇이겠는가? 볼포 여러분들은 어떻게 생각하시는가? 이 버그를 찾아내면서 델파이 컴파일러가 이런 경우에 왜 경고를 때리지 않는지 참으로 안타까울 뿐이다.
|