어설 션이 함수가 아닌 매크로 인 이유는 무엇입니까?
제 강사가 수업 시간에 그 질문을했는데 왜 함수가 아닌 매크로인지 궁금합니다.
간단한 설명은 표준이 요구하는 것 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.h
Standrd 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) 대 범위 블록 이 어떤 경우에는 바람직하지 않은 영향을 미치는 것을 알 수 있습니다.
- 파일 (을 통해
__FILE__
) 및 줄 번호 (를 통해__LINE__
) 를 캡처 할 수 있습니다. - 릴리스 모드에서 빌드 할 때
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
'Development Tip' 카테고리의 다른 글
Code :: Blocks 컴파일러에 C ++ 11 지원을 추가하려면 어떻게해야합니까? (0) | 2020.12.10 |
---|---|
Java에서 HashMap 키 및 값 반전 (0) | 2020.12.10 |
Swift의 문자열에서 분음 부호를 제거하는 방법은 무엇입니까? (0) | 2020.12.10 |
Swift로 프로그래밍 방식으로 로케일을 어떻게 변경할 수 있습니까? (0) | 2020.12.10 |
파일 또는 어셈블리 'Microsoft.Build.Framework'(VS 2017)를로드 할 수 없습니다. (0) | 2020.12.10 |