E2283 Too many local constants. Use shorter procedures 에러

Delphi5로 작업된 대규모 프로젝트를 Delphi XE3로 마이그레이션하던 중, E2283이라는 생소한 컴파일 에러를 만났습니다.

E2283 error

 

이 에러에 대해 온라인 헬프를 살펴보면 다음과 같이 설명되어 있는데요.

E2283 Too many local constants. Use shorter procedures

One or more of your procedures contain so many string constant expressions that they exceed the compiler's internal storage limit. This can occur in code that is automatically generated. To fix this, either shorten your procedures or declare constant identifiers instead of using so many literals in the code.

The DCC32 and DCCOSX compilers produce E2283 when the code generator gives up after literal/const values exceed 64Kbytes. This 64K limitation applies to string, set, and floating-point values in expressions of a function body, and the limitation is per function.
Currently, the DCC64 compiler does not produce E2283.

컴파일러에는 내부 저장 공간에 한계가 있어서(64KB) 너무 많은 스트링 상수를 사용할 경우 이 에러가 난다는 얘깁니다. 이걸 피하려면 프로시저를 줄이거나, 혹은 직접 문자열 표현(리터럴)을 줄이고 대신 상수(const) 선언을 쓰라는 건데요.

일단, Delphi5에서는 정상적으로 컴파일되었고 십수년간 사용하던 코드인데 델파이 최근 버전들에서는 에러가 나는 것은, 아마도 델파이 2009 이후로 유니코드가 도입되면서 문자열의 한 문자 단위 저장공간이 1바이트가 아닌 2바이트가 되어버렸기 때문에 2배의 메모리를 차지해서인 것으로 보입니다. 실제로 이 에러 메시지로 구글링해보면 2007까지는 에러가 나지 않았는데 2009에서 에러가 난다는 글들이 여럿 있더군요.

그런데, 실제로는 이 헬프에서 안내하는 해결책이 틀렸습니다. 제가 에러에 부딛힌 소스코드에서는, 이 에러가 난 원인이 아주! 긴 SQL문들 때문이었는데요. 리터럴로 코드에 직접 박아놓은 것이 아니라 const 상수로 선언되어 있습니다. 이미 const 상수로 선언되어 있는데도 에러가 나고요. 더욱이 엄청나게 긴 SQL문 자체를 더 줄일 방법도 없습니다. 그러니까 다르게 해결할 방법이 없는 거죠.

당장 컴파일이 안되니, 더 진도를 나갈 수도 없고 갑갑한 상황이 되었습니다. 아주 긴 SQL 문을 다루는 업무 시스템을 다루는 분들은 종종 같은 문제에 부딛힐 것입니다.

이 문제를 해결할 방법을 꽤 오랫동안 고민하다가, 일단 피해갈 간단한 트릭을 생각해냈습니다. 이 문자열들을 const가 아닌 var 변수로 만들어버리는 거죠. 그리고 초기값 문자열을 지정해줘야 하니까 지역 변수는 안되고, 전역 변수로 바꾸는 겁니다. 그러니까, const로 선언된 상수 SQL문을 전역 영역으로 옮기고, const 대신 var 선언으로 바꾸고, 문자열 이름 뒤에 string 타입을 지정해줬습니다.

위와 같이 선언되어 있었던 것을,

이렇게 바꿔준 겁니다. 물론 function이나 procedure의 바깥에서 해줘야 문자열 리터럴로 초기화가 가능하죠.

이렇게 바꿔줌으로써 E2283 에러를 회피할 수 있었습니다.

참고로, 처음에는 이 const를 resourcestring으로 바꾸려고 시도도 해봤는데요. resourcestring은 아예 4096바이트까지만 가능하다고 에러가 나더군요.

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.