#define 이 왜?
1. 상수를 정의할 때,
디버깅이 안된다.
왜 디버깅이 안될까?
=> 컴파일 시점에 상수로 바꾼다.
=> symbol table에 들어가지 않는다.
요새는 ide가 해주겠지만, 에러 로그 등에서 확인할 때, 상수명이 아니라 153.2121 같이 숫자 자체가 찍히기 때문에 디버깅하기 어려워 질 수 있다.
#include <iostream>
#define ASPECT_RATIO 1.653
void func(float a);
int main()
{
if (ASPECT_RATIO > 2) {
// do someting;
}
// 1000줄 코드...
func(ASPECT_RATIO);
// 1000줄 코드...
std::cout << ASPECT_RATIO;
}
이 코드에서 translation unit을 만들면 어떻게 될까?
clang -E fileName.cpp > fileName.pre
이런 식으로 상수로 바뀐다.
symbol table은 무엇일까?
assembler의 symbol table, compiler의 symbol table이 따로 존재한다. 지금은 compiler level의 symbol table을 알아보자.
- 컴파일러에 의해 생성되고 관리되는 "변수명", "함수명", objects, classes, interfaces 등에 대한 자료구조이다.
- 심볼 테이블은 symbol name, type, scope로 구성되고, 드물게 주소가 포함될 때도 있다.
- 컴파일러의 Analysis, Synthesis 단계 모두에서 해당 기호가 정의되었는지, 정확한지 검증하기 위해 사용되고, 이를 통해 중간 코드나 타겟 코드를 만들게 된다.
- 링킹과정에서 링커가 심볼 테이블을 보
- 더 자세한 내용은 아래 링크를 보자.(허수는 안보고 넘어감)
https://www.tutorialspoint.com/compiler_design/compiler_design_symbol_table.htm
https://iq.opengenus.org/symbol-table-in-compiler/
대신에 const 또는 enum을 사용해보자.
const double AspectRatio = 1.653;
class MyClass { private: enum { NumTurns = 5 } };
2. 매크로 함수를 만들때,
매크로 함수 인자로 표현식을 넣었다면, 평가를 여러번하는 오류가 발생할 수 있다.
이런 문제를 해결하기 위해 인라인 함수로 대체해보자.
매크로 처럼 효율적이고, 타입 안정성까지 취할 수 있다.
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
이런 매크로 함수가 있을 때,
int a = 5;
CALL_WITH_MAX(++a, 0);
CALL_WITH_MAX(++a, 10);
평가가 여러번 될 수 있다.