본문 바로가기
프로그래밍 놀이터/iOS

[Effecitve Objective-C] #4 전처리기 #define 보다는 타입이 있는 상수를 사용하라

by 돼지왕 왕돼지 2017. 7. 24.
반응형

 [Effecitve Objective-C] #4 전처리기 #define 보다는 타입이 있는 상수를 사용하라


출처 : Effective Objective-C


#define, compile unit, const, convention, duplicate symbol, effective objective-c, Extern, external symbol, global symbol table, k prefix, name space, o 파일, object file, preprocessor, static, static const, translation unit, [Effecitve Objective-C] #4 전처리기 #define 보다는 타입이 있는 상수를 사용하라, 구현 파일, 번역 단위, 상수, 상수 정의, 상수값 치환, 실수, 외부 공개, 외부 노출, 외부 심벌, 재선언, 전역 심벌 테이블, 전처리기, 전처리기 상수, 전처리기 지시어, 접두어, 컴파일 단위, 컴파일러, 컴파일러 치환, 클래스, 클래스 이름, 클래스 이름 접두어, 타입 정보, 헤더


-

#define 은 전처리기 지시어이다. (preprocessor)



-

#define 정의는 타입에 대한 정보가 없다.



-

#define 이 헤더 파일에 선언되어 있다면 그 헤더 파일을 포함하는 모든 곳에서 #define 으로 정의한 상수값을 치환한다.



-

preprocessor 보다는 상수를 정의하는 것이 항상 더 좋은 방법이다.


// implementation


static const NSTimeInterval kAnimatinoDuration = 0.3;


@implementation


@end



-

상수의 일반적인 표기법은 k 소문자를 상수 맨 앞에 붙이는 것이다.

클래스 외부로 노출되는 상수는 일반적으로 클래스 이름을 상수 앞에 붙여준다.



-

상수를 어느 곳에 정의하느냐도 중요하다.

정적 상수(static const)는 헤더 파일에 있으면 안 된다.

Objective-C 는 네임스페이스(name space)라는 개념이 없기 때문에 kAnimationDuration 이라는 전역변수로 정의된다.

이 이름은 ClassNameAnimationDuration 처럼 사용될 범위를 나타내는 접두어를 반드시 붙여야 한다.



-

외부로 노출할 필요가 없는 상수는 사용되는 구현 파일에 정의해야 한다.



-

변수를 static, const 둘 다 이용해 선언하는 것이 중요하다.

const 식별자는 해당 변수의 값을 변경하려고 하면 컴파일러가 오류를 발생시키는 것을 의미한다.

static 식별자는 변수가 정의된 번역 단위(translation unit)의 지역 변수라는 것을 의미한다.

컴파일러가 최종적으로 번역 단위를 입력받아 목적 파일(object file) 을 만들어낸다.

Objective-C 의 경우 이는 클래스당(모든 구현 파일) 한 개의 번역 단위가 있다는 것을 의미한다.


변수가 static 으로 선언되지 않으면 컴파일러는 그것을 위해 외부 심벌(external symbol)을 생성할 것이다.

다른 번역 단위가 같은 이름의 변수를 선언하면 링커는 duplicate symbol 에러를 일으킬 것이다.


cf)

translation unit : o 파일을 만들어내기 위해 컴파일러에 전달하는 최종 입력 파일.

이 말은 소스 파일에서 #include 로 포함된 헤더 파일을 포함하는 것 같은 pre processor 작업이 끝난 파일이라는 뜻이다.

컴파일 단위 (compile unit)이라고도 한다.



-

변수를 static const 모두 이용해 선언할 때 컴파일러는 "절대 심벌"을 만들지 않는다.

대신 전처리기 정의되었을 때 하는 것처럼 사용된 모든 변수를 값으로 치환한다.

단, 타입 정보가 제공된다는 이점이 있다.



-

상수를 외부로 공개해야 할 때가 있다.

그런 상수는 상수를 정의한 번역 단위 밖에서 사용할 수 있게 전역 심벌 테이블(global symbol table)에 넣을 필요가 있다.

이러한 상수는 extern 을 사용하여 정의한다.


// header

extern NSString* const EOCStringConstant;


// implementation

NSString* const EOCStringConstant = @“VALUE”;


상수는 헤더 파일에 선언되고 구현 파일에 정의된다.

상수 타입에 const 식별자를 두는 것이 중요하다.



-

심벌이 전역 심벌 테이블에 있다는 사실 때문에 그런 상수의 이름은 주의 깊게 지어야 한다.

상수와 연관된 클래스 이름을 접두어로 사용하는 것은 신중한 행동이고 잠재적으로 이름이 겹치는 것을 막아준다.



-

상수로 정의하는 것이 전처리기 상수 정의보다 훨씬 좋다.

상수의 값이 변하지 않는다는 것을 보장해준다.

전처리기 선언은 실수로 재선언될 수 있다.


결론은 상수가 필요할 때 전처리기 정의는 피하고, 대신 구현 파일에 static const 전역으로 선언한 것 같은,

컴파일러가 볼 수 있는 상수를 사용하라.



-

기억할점


     전처리기 정의는 피하라.

     이것은 타입에 대한 정보가 없다.

     컴파일하기 전에 단지 해당 정의를 찾아서 치환할 뿐이다.

     또한 경고 없이 재정의될 수 있다.

     이로 인해 앱 내에서 값의 일관성이 깨지는 문제를 야기할 수 있다.


     static const 를 사용해 구현 파일에 파일에 한정된 상수를 선언하라.

     이러한 상수는 전역 심벌 테이블에 공개되지 않을 것이다.

     그래서 그런 상수 이름은 네임스페이스를 필요로 하지 않는다.


     헤더 파일에 extern 을 이용해 전역 상수를 선언하라.

     그리고 연관된 구현 파일에 값을 정의하라.

     이러한 상수는 전역 심벌 테이블에 나타날 것이다.

     그리고 그런 상수 이름은 네임스페이스가 있어야 한다.

     일반적으로 관련된 클래스 이름을 접두어로 사용한다.




반응형

댓글