Development Tip

어설 션이 함수가 아닌 매크로 인 이유는 무엇입니까?

yourdevel 2020. 12. 10. 21:22
반응형

어설 션이 함수가 아닌 매크로 인 이유는 무엇입니까?


제 강사가 수업 시간에 그 질문을했는데 왜 함수가 아닌 매크로인지 궁금합니다.


간단한 설명은 표준이 요구하는 것 assert우리가 보면, 매크로로 초안 C99 표준 ( 지금까지 나는 섹션에서 동일 말할 수로 초안 C11 표준 뿐만 아니라 절) 7.2 진단2 말합니다 :

assert 매크로는 실제 기능이 아닌 매크로로 구현되어야합니다. 실제 함수에 액세스하기 위해 매크로 정의가 억제되면 동작이 정의되지 않습니다.

이것이 필요한 이유는 국제 표준 의 이론적 근거 — 프로그래밍 언어 —C에 제시된 근거 는 다음과 같습니다.

진정한 기능을 주장하는 것은 어렵거나 불가능할 수 있으므로 매크로 형식으로 제한됩니다.

그다지 유익하지는 않지만 다른 요구 사항에서 그 이유를 알 수 있습니다. 섹션 7.2단락 1로 돌아 가면 다음과 같이 말합니다.

[...] NDEBUG가 포함 된 소스 파일의 지점에서 매크로 이름으로 정의되면 assert 매크로는 다음과 같이 정의됩니다.

#define assert(ignore) ((void)0)

assert 매크로는 포함될 때마다 NDEBUG의 현재 상태에 따라 재정의됩니다.

이는 잠재적으로 값 비싼 검사 비용을 부담 할 수있는 릴리스 모드에서 어설 션을 쉽게 해제 할 수있는 방법을 제공하므로 중요합니다.

그리고 두 번째로 중요한 요구 사항은이 매크로를 사용하는 데 필요한 것입니다 __FILE__, __LINE__그리고 __func__섹션에 덮여있는 7.2.1.1 어설 매크로 말한다 :

[...] assert 매크로는 실패한 특정 호출에 대한 정보를 기록합니다. [...] 후자는 각각 표준 오류 스트림의 전처리 매크로 __FILE_ _ 및 __LINE_ _ 및 식별자 __func_ _)의 값입니다. 구현 정의 형식. 165) 그런 다음 중단 기능을 호출합니다.

각주가 165말하는 :

작성된 메시지는 다음과 같은 형식 일 수 있습니다.

Assertion failed: expression, function abc, file xyz, line nnn.

그것을 매크로로 사용하면 매크로 __FILE__등을 적절한 위치에서 평가할 수 있으며 Joachim이 매크로라는 점을 지적 하면 생성하는 메시지에 원래 표현식 을 삽입 할 수 있습니다 .

C ++ 표준 초안에서는 cassert헤더 의 내용이 assert.hStandrd C 라이브러리 헤더 와 동일해야합니다 .

내용은 표준 C 라이브러리 헤더와 동일합니다.

참조 : ISO C 7.2.

왜 (무효) 0?

(void)0아무 일도하지 않는 다른 표현과 반대로 사용 하는 이유 는 무엇입니까? 몇 가지 이유를 생각해 낼 수 있습니다. 먼저 assert 시놉시스가 섹션에 표시되는 방식입니다 7.2.1.1.

void assert(scalar expression);

그리고 그것은 말한다 ( 내 강조 ) :

assert 매크로는 진단 테스트를 프로그램에 적용합니다. 그것은 void 식으로 확장됩니다.

이 식은 void 식(void)0 으로 끝나야하는 필요성과 일치 합니다 .

우리가 요구 사항을 가지고 있지 않은 가정하면, 다른 가능한 표현 등의 허용 용도와 같은 바람직하지 않은 효과를 가질 수 assert사용 예를 들어 디버그 모드에서 허용되지 않는다 릴리스 모드에서 일반을0 우리가 사용할 수 있도록 할 assert과제와 가능성 생성 할 올바르게 사용하는 경우를 expression result unused경고. 주석에서 알 수 있듯이 복합 문 을 사용하는 것과 관련하여 C 멀티 라인 매크로에서 do / while (0) 대 범위 블록 이 어떤 경우에는 바람직하지 않은 영향을 미치는 것을 알 수 있습니다.


  1. 파일 (을 통해 __FILE__) 및 줄 번호 (를 통해 __LINE__) 를 캡처 할 수 있습니다.
  2. 릴리스 모드에서 빌드 할 때 assert아무 작업도하지 않는 유효한 표현식 (예 :)으로를 대체 할 수 있습니다.((void)0)

을 포함하는 순간 NDEBUG라는 이름의 매크로가 이미 정의 된 경우이 매크로는 비활성화됩니다. 이를 통해 코더는 프로그램을 디버깅하는 동안 소스 코드에 필요한만큼의 assert 호출을 포함하고 다음과 같은 행을 포함하여 프로덕션 버전에 대해 모두 비활성화 할 수 있습니다.

#define NDEBUG 

을 포함하기 전에 코드 시작 부분에 <assert.h>.

따라서이 매크로는 일반적으로 프로그램이 디버깅 단계를 종료 한 후에 비활성화되므로 사용자 또는 런타임 오류가 아닌 프로그래밍 오류를 캡처하도록 설계되었습니다.


함수로 만들면 일부 함수 호출이 증가하고 릴리스 모드에서 이러한 모든 어설 션을 제어 할 수 없습니다.

경우에 당신은 다음 기능을 사용 _FILE__, __LINE__그리고 __func__주장 기능의 코드의 값을 제공 할 것입니다. 호출 라인이나 호출 함수 라인이 아닙니다.


일부 주장은 호출 비용이 많이들 수 있습니다. 방금 고성능 매트릭스 반전 루틴을 작성했고 온 전성 검사를 추가했습니다.

assert(is_identity(matrix * inverse))

끝까지. 글쎄요, 당신의 행렬은 꽤 크고 assert함수라면 assert에 전달하기 전에 계산을 수행하는 데 많은 시간이 걸립니다. 디버깅을하지 않는다면 정말 낭비하고 싶지 않은 시간입니다.

또는 어설 션이 비교적 저렴하지만 내부 루프에서 호출되는 매우 짧은 함수에 포함되어있을 수 있습니다. 또는 다른 유사한 상황.

assert대신 매크로 를 만들면 어설 션이 꺼져있을 때 계산을 완전히 제거 할 수 있습니다.


어설 션이 함수가 아닌 매크로 인 이유는 무엇입니까?

DEBUG 모드에서 컴파일되어야하고 RELEASE 모드 에서 컴파일되지 않아야하기 때문 입니다.

참고 URL : https://stackoverflow.com/questions/25285557/why-is-assert-a-macro-and-not-a-function

반응형