이 클레임이 발생한 경우 multipletimes이 무엇을 의미하는지 알 수 없습니다. 결과 코드는 일반 C 컴파일러를 사용하여 컴파일되므로 결국 다른 코드와 마찬가지로 (또는 거의) 유형을 검사하지 않게됩니다.C 매크로는 유형이 안전하지 않은 이유는 무엇입니까?
매크로가 왜 형식이 안전하지 않은 이유는 무엇입니까? 그것은 그들이 악으로 간주되어야하는 주된 이유 중 하나 인 것으로 보인다.
이 클레임이 발생한 경우 multipletimes이 무엇을 의미하는지 알 수 없습니다. 결과 코드는 일반 C 컴파일러를 사용하여 컴파일되므로 결국 다른 코드와 마찬가지로 (또는 거의) 유형을 검사하지 않게됩니다.C 매크로는 유형이 안전하지 않은 이유는 무엇입니까?
매크로가 왜 형식이 안전하지 않은 이유는 무엇입니까? 그것은 그들이 악으로 간주되어야하는 주된 이유 중 하나 인 것으로 보인다.
자들이 직접 형태 보증 ... 내가 특정 시나리오에서 가정하지 않는/당신은 그들이 간접적으로 (즉, 결과 코드) 할 수 있습니다 주장 입력 안전 할 수 용도. 하지만 정수를위한 매크로를 만들 수 있고 문자열을 전달할 수 있습니다 ... 매크로를 처리하는 전처리 기는 확실히 신경 쓰지 않습니다. 컴파일러는
이것은 좋은 것처럼 들리지만 누군가는 세상에 이것이 어떤 식 으로든 매크로를 만들어 내지 않으면 생성 될 수 있다는 것을 지적해야합니다. 그렇지 않으면 그렇지 않으면 복제 될 수 있습니다. :) – Sarien
한때 공동 작업자가 printf를 코어 헤더 파일 중 하나의 다른 것으로 정의한 프로젝트에서 한 번 작업했습니다. –
매크로가 실행되면 소스 파일을 통해 텍스트가 일치합니다. 이는 컴파일 전이므로 변경된 데이터 유형을 인식하지 못합니다.
컴파일이 완료되기 전에 유형이 검사되는 곳에서 완료되었다고 했으므로 그 점이 저를 혼란에 빠지게합니다. – Sarien
일반적인 형식 시스템을 사용하여 컴파일러를 통해 코드가 모두 컴파일된다는 것은 사실입니다. 그러나 매크로 확장 단계 자체는 데이터 형식을 고려하지 않습니다. 컴파일이 시작되기 전에 발생하기 때문에 –
특히 MSDN 링크에서 함수 매크로에 대해 이야기합니다 (예 : http://stackoverflow.com/questions/163365/). make-ac-macro-behaviour-like-a-function)은 두 입력을 인식하고 함께 추가하지만 컴파일러가 수행하는 방식을주의 깊게 검사하지 않고 예를 들어 –
전형적인 "최대"매크로를 고려 ... 용도에 따라, 거기에 질식 할 수 있습니다, 대 기능 : 여기
#define MAX(a,b) a < b ? a : b
int max(int a, int b) {return a < b ? a : b;}
은 매크로 입력 - 안전하지 않는에서 말할 때 사람들이 무엇을 의미하는지의 방법은 함수는 다음 함수의 호출자가
char *foo = max("abc","def");
컴파일러가 경고합니다 기록
합니다.
는 반면 매크로의 호출은 쓰면 :
가char *foo = MAX("abc", "def");
전처리와 그 대체됩니다 : 아무런 문제없이 컴파일하지만, 거의 확실하게 결과를 당신에게 제공하지 않습니다
char *foo = "abc" < "def" ? "abc" : "def";
원했어.
또한 부작용이 다른 물론 함수 케이스를 고려해
int x = 1, y = 2;
int a = max(x++,y++);
최대() 함수 이후에 적용 할 x 및 y 및 사후 증분의 원래 값 작동
함수가 반환됩니다. 매크로 경우
: 두 번째 라인이 제공하는 전처리
int x = 1, y = 2;
int b = MAX(x++,y++);
것을 :
int b = x++ < y++ ? x++ : y++;
가 다시, 어떤 컴파일러 경고 또는 오류 만이 예상 행동이있을 수 없습니다.
매크로는 형식을 이해하지 못하기 때문에 형식이 안전하지 않습니다.
매크로에만 정수를 사용할 수는 없습니다. 전 처리기는 매크로 사용을 인식하고 토큰 시퀀스 (인수가있는 매크로)를 다른 토큰 세트로 대체합니다. 이 기능은 올바르게 사용하면 강력한 기능이지만 잘못 사용하는 것은 쉽습니다.함수와
당신은 기능 void f(int, int)
를 정의 할 수 있습니다 컴파일러 플래그는 F의 반환 값을 사용하거나 문자열 통과하려고한다면.
매크로가 없습니다. 유일한 수표는 올바른 수의 인수가 주어진 것입니다. 토큰을 적절하게 바꾸고 컴파일러로 전달합니다.
#define F(A, B)
은 ... 당신이 F(1, 2)
, 또는 F("A", 2)
또는 F(1, (2, 3, 4))
또는 전화를 할 수
당신은 컴파일러에서 오류를 얻을 수 있습니다, 또는 당신은 수도 있지, 매크로 내에서 어떤 유형의 일종을 필요로하는 경우 안전. 하지만 전처리 기가 아닙니다. 숫자 기대 매크로에 문자열을 전달할 때 기회가 컴파일러에서 찍찍없이 숫자로 문자열 주소를 사용하게 될 겁니다만큼
당신은, 매우 이상한 결과를 얻을 수 있습니다. 매크로 처리기에 의해 처리되며, 전처리 유형을 이해하지 않기 때문에
C++ 템플릿에 대해서도 마찬가지입니다. 템플리트는 유형 안전하지 않습니다. –
, 그것은 행복하게 잘못된 형식의 변수를 받아 들일 것입니다.
이 보통 기능과 같은 매크로에 대해서만 관심, 그리고 어떤 종류의 오류는 종종 전처리하지 않는 경우에도 컴파일러에 의해 잡힐 것입니다,하지만이 보장되지 않습니다. 당신이 편집 컨트롤에 풍선 팁을 보여주고 싶었다 경우
예
윈도우 API에서, 당신은 Edit_ShowBalloonTip을 사용하십시오. Edit_ShowBalloonTip은 편집 컨트롤에 대한 핸들과 EDITBALLOONTIP 구조에 대한 포인터의 두 가지 매개 변수를 취하는 것으로 정의됩니다. 그러나 Edit_ShowBalloonTip(hwnd, peditballoontip);
는 일반적으로 그들에게 메시지를 전송하여 이루어집니다 컨트롤을 구성하기 때문에
SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)(peditballoontip));
로 평가되는 매크로 실제로, Edit_ShowBalloonTip
이 구현에서 배역을 할 수있다, 그러나 오히려 인라인 함수보다 매크로이기 때문에, 그것의 peditballoontip 매개 변수에서 어떤 타입 검사도 할 수 없습니다.
여담
는 흥미롭게도, 때때로 C++ 인라인 함수는 약간에게 있습니다 너무 형 안전합니다. 매크로 표준 C MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
와 C++ 인라인 버전
template<typename T>
inline T max(T a, T b) { return a > b ? a : b; }
MAX (1, 2U) 예상대로 작동하지만 최대 (1, 2U)를 고려하지 않습니다.
이 정말 대부분의 경우 매크로를 사용하여의 인수 (그들은 악을 아직도)하지 (1 및 2U는 다른 유형이기 때문에, 최대는. 그들 모두 인스턴스화 할 수없는), 그러나 그것은이다 C 및 C++의 유형 안전성에 대한 흥미로운 결과입니다.
Windows API 예제는 캐스트가 아닌 인수를 취하는 함수처럼 보이지만 실제로는 거의 모든 쓰레기를 전달할 수 있습니다. – Joel
"* ... 잘못된 형식의 변수를 기꺼이 받아 들일 것입니다. *"매크로 매개 변수가 형식화되지 않았기 때문에이 문장이 의미가 없기 때문에 잘못되었거나 올바른 형식이 없습니다. – alk
@alk : 요점이 아닌가요? * 확실한 것은 틀린 타입이다. 같은 의미에서 타입이없는 언어는 예기치 않은 형식의 데이터를 제공하는 함수를 가질 수있다. 유형 없음, 유형 안전 없음. 그것은 여기서의 질문에 대한 해답입니다. – Phoshi
매크로가 더 적은 유형의 안전 기능을보다 상황이 있습니다. 예 :
void printlog(int iter, double obj)
{
printf("%.3f at iteration %d\n", obj, iteration);
}
인수를 역순으로 지정하면 잘림과 잘못된 결과가 발생하지만 위험하지는 않습니다. 반대로
#define PRINTLOG(iter, obj) printf("%.3f at iteration %d\n", obj, iter)
은 정의되지 않은 동작을 일으 킵니다. 공정하게보기 위해 GCC는 후자에 대해 경고하지만 이전에는 그렇지 않다고 경고합니다. 그러나 다른 varargs 함수에 대해서는 printf
을 알고 있기 때문에 그 결과는 잠재적으로 재앙입니다.
매크로는 유형 안전이 보장되지 않았기 때문에 유형 안전하지 않습니다.
매크로가 확장 된 후 컴파일러에서 형식 검사를 수행합니다.
매크로 및 확장은 C 소스 코드의 "게으른"저자 (작가/독자라는 의미)의 도우미 역할을합니다. 그게 다야.
C++ 템플릿에서도 마찬가지입니다. 컴파일러는 * after * 템플릿 만 확장 (인스턴스화) 된 형식 검사를 수행합니다. 따라서 매크로는 C++ 템플릿보다 덜 형식 안전합니다. 컴파일러 *는 결국 최종 생성 된 코드에서 유형을 확인하기 때문에 둘 다 간접적으로 유형에 안전합니다. 어느 쪽도 C++ 템플릿이 아닌 * 타입 *이 타입 체크 된 직접 타입 안전하지 않습니다. –
요점은 C 컴파일러가 매크로 정의를 다루지 않는다는 점입니다. 전 처리기가 그것들을 처리합니다. –
그래, 그렇지만 생성 된 코드가 실제로 유형 시스템을 위반한다면 컴파일러는이를 잡아낼 것입니다. – Sarien
C++ FAQ는 왜 매크로가 악의적 인 이유에 대해 확실하게 다루고 있습니다. http://www.parashift.com/c++-faq-lite/inline-vs-macros.html –