매크로는 다른 도구와 같습니다. 살인에 사용되는 망치는 망치이기 때문에 악의가 없습니다. 그 사람이 그런 식으로 사용하는 방식은 악합니다. 못으로 망치고 싶다면 망치가 완벽한 도구입니다.
매크로를 "나쁜"것으로 만드는 몇 가지 측면이 있습니다 (나중에 각각에 대해 자세히 설명하고 대안을 제안 할 것입니다).
- 매크로를 디버그 할 수 없습니다.
- 매크로 확장은 이상한 부작용을 일으킬 수 있습니다.
- 매크로에는 "네임 스페이스"가 없으므로 다른 곳에서 사용 된 이름과 충돌하는 매크로가있는 경우 원하지 않는 위치에서 매크로가 대체되고 일반적으로 이상한 오류 메시지가 표시됩니다.
- 매크로는 인식하지 못하는 것에 영향을 미칠 수 있습니다.
여기에서 조금 확장 해 보겠습니다.
1) 매크로는 디버깅 할 수 없습니다.
숫자 나 문자열로 변환되는 매크로가있는 경우 소스 코드에는 매크로 이름이 있고 많은 디버거가 있으면 매크로가 무엇으로 변환되는지 "볼"수 없습니다. 그래서 당신은 실제로 무슨 일이 일어나고 있는지 알지 못합니다.
교체 : 사용 enum
또는const T
"함수와 유사한"매크로의 경우 디버거가 "현재있는 소스 행당"수준에서 작동하기 때문에 매크로가 하나의 명령문이든 100 개이든 상관없이 단일 명령문처럼 작동합니다. 무슨 일이 일어나고 있는지 파악하기 어렵게 만듭니다.
대체 : 함수 사용- "빠름"이 필요한 경우 인라인 (하지만 너무 많은 인라인은 좋지 않음)
2) 매크로 확장은 이상한 부작용을 일으킬 수 있습니다.
유명한 것은 #define SQUARE(x) ((x) * (x))
그리고 사용 x2 = SQUARE(x++)
입니다. 이로 x2 = (x++) * (x++);
인해 유효한 코드 [1]이더라도 프로그래머가 원하는 바가 거의 확실하지 않습니다. 함수라면 x ++를해도 괜찮을 것이고 x는 한 번만 증가 할 것입니다.
또 다른 예는 매크로의 "if else"입니다.
#define safe_divide(res, x, y) if (y != 0) res = x/y;
그리고
if (something) safe_divide(b, a, x);
else printf("Something is not set...");
실제로 완전히 잘못된 것이됩니다 ....
교체 : 실제 기능.
3) 매크로에는 네임 스페이스가 없습니다.
매크로가있는 경우 :
#define begin() x = 0
그리고 begin을 사용하는 C ++ 코드가 있습니다.
std::vector<int> v;
... stuff is loaded into v ...
for (std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
std::cout << ' ' << *it;
이제 어떤 오류 메시지가 발생한다고 생각하고 오류를 어디에서 찾습니까? [다른 사람이 작성한 일부 헤더 파일에있는 시작 매크로를 완전히 잊었거나 알지 못했다고 가정 할 때]? [포함하기 전에 해당 매크로를 포함하면 훨씬 더 재미 있습니다. 코드 자체를 볼 때 전혀 의미가없는 이상한 오류에 빠져들 것입니다.
대체 : "규칙"만큼 대체는 없습니다. 매크로에는 대문자 이름 만 사용하고 다른 항목에는 모두 대문자 이름을 사용하지 마십시오.
4) 매크로에는 사용자가 알지 못하는 효과가 있습니다.
이 기능을 사용하십시오.
#define begin() x = 0
#define end() x = 17
... a few thousand lines of stuff here ...
void dostuff()
{
int x = 7;
begin();
... more code using x ...
printf("x=%d\n", x);
end();
}
이제 매크로를 보지 않고도 begin이 x에 영향을 미치지 않는 함수라고 생각할 것입니다.
이런 종류의 것, 그리고 훨씬 더 복잡한 예제를 보았습니다. 정말 당신의 하루를 망칠 수 있습니다!
대체 : 매크로를 사용하여 x를 설정하거나 x를 인수로 전달하십시오.
매크로를 사용하는 것이 확실히 유익 할 때가 있습니다. 한 가지 예는 파일 / 라인 정보를 전달할 매크로로 함수를 래핑하는 것입니다.
#define malloc(x) my_debug_malloc(x, __FILE__, __LINE__)
#define free(x) my_debug_free(x, __FILE__, __LINE__)
이제 my_debug_malloc
코드에서 일반 malloc으로 사용할 수 있지만 추가 인수가 있으므로 마지막에 "어떤 메모리 요소가 해제되지 않았는지"스캔하면 할당 된 위치를 인쇄 할 수 있습니다. 프로그래머는 누수를 추적 할 수 있습니다.
[1] "시퀀스 포인트에서"하나의 변수를 두 번 이상 업데이트하는 것은 정의되지 않은 동작입니다. 시퀀스 포인트는 문장과 정확히 같지는 않지만 대부분의 의도와 목적에 대해 우리가 그것을 고려해야하는 것입니다. 이렇게 x++ * x++
하면 x
두 번 업데이트되며 , 이는 정의되지 않았으며 아마도 다른 시스템에서 다른 값으로 이어질 것이고 다른 결과 값으로 이어질 것입니다 x
.
#pragma
매크로가 아닙니다.