"어설 션"기능이란 무엇입니까?


262

OpenCV 튜토리얼을 공부하고 assert기능을 접했습니다 . 무엇을합니까?


20
남자 어설에서 메모를 주목하라 : "어설 () 매크로로 구현, 테스트 표현식이 부작용이있는 경우, 프로그램 동작은 NDEBUG가 정의되어 있는지 여부에 따라 달라집니다이 켜져 디버깅 할 때 사라지는 Heisenbugs (불확정성 버그)를 만들 수 있습니다. "
Johannes Schaub-litb


35
@ S.Lott는 이제 Google을 검색하는 사람들이이 페이지를 상위 검색 결과 중 하나로 찾게되어 질문에 대한 좋은 동료 리뷰 답변을 제공하고 동시에 스택 오버플로를 홍보하므로 나에게 +1이됩니다!
매트 그럼

6
나에게서 -1입니다. 가장 많이 검색된 결과는 먼저 OP가 참조해야 할 문서 입니다.
궤도에서 가벼움 경주

9
@LightnessRacesinOrbit. 나에게 게으른 전화, 그러나 나는 자신과 같은 지식이 많은 SO 사용자가 제공하는 훌륭한 요약, 요약 및 설명 문서를 사용하는 것을 선호합니다. 나의 진심으로 감사합니다 :)
Tyson Hilmer

답변:


298

assert인수가 거짓으로 판명되면 프로그램 (일반적으로 assert 문을 인용하는 메시지와 함께)을 종료합니다. 예상치 못한 조건이 발생하면 프로그램이 더 확실하게 실패하도록 디버깅하는 동안 일반적으로 사용됩니다.

예를 들면 다음과 같습니다.

assert(length >= 0);  // die if length is negative.

다음과 같이 실패한 경우 표시 할보다 유용한 메시지를 추가 할 수도 있습니다.

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

또는 이와 같이 :

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

릴리스 (비디 버그) 빌드를 수행 할 때 일반적으로 컴파일러 스위치를 사용 assert하여 NDEBUG매크로 를 정의하여 명령문 평가의 오버 헤드를 제거 할 수도 있습니다 . 이것의 결과는 프로그램이 어설 션 매크로 실행에 의존 해서는 안된다는 것 입니다.

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here's a safer way:
int ret = foo();
assert(ret);

abort ()를 호출하고 아무것도하지 않는 프로그램의 조합에서, 주장은 사용자가 문자 대신 숫자를 입력하는 것보다는 개발자가 가정 한 것을 테스트하는 데만 사용해야합니다. 다른 방법으로 처리).


49
" assert일반적으로 예외가 발생합니다"– C ++에서는 "예외"가 발생하지 않으며 중단이라고 부릅니다. 조금 다릅니다.
Artyom

5
이 답변이 질문에 태그가 지정된 것과 같은 언어에 관한 것이라고 생각하지 않습니다 (C 및 C ++). C 및 C ++에서 assert는 예외를 발생시키지 않으며 인수 주위에 괄호가 있으며 #문자는 주석을 나타내지 않습니다.
Steve Jessop

옵션은 다음과 같습니다. 커뮤니티 위키에 답하고 이전 내용을 제거하고 다른 사람들이 올바른 정보를 배치하도록 요청하여 질문을 편집하십시오. 그렇게하면 다운 보트는 담당자에게 영향을 미치지 않으며 사람들이 답을 향상시킬 수 있습니다.
Johannes Schaub-litb

2
길이가 NaN 인 경우 length> = 0도 false로 나타납니다
Andreas

1
현재 VS 2015에서는 오류 메시지가있는 어설 션이 잘못되어 작동하지 않습니다. 그것은해야한다assert("error message", expression)
Dooskington

102

어설 션 컴퓨터 문은 문 유사 확인 영어있다.


131
글쎄요 "표시등이 꺼져 있는지 확인하십시오"는 "표시등이 꺼져 있는지 확인하고 폭발하지 않는지 확인하십시오"가 아니라 "표시등이 켜져 있는지 확인하고 끄십시오"를 의미합니다. “더블 체크”는 더 밀접한 번역입니다.
Luke Maurer

7
@Luke는 영어의 경이를 보여줍니다. 언어는 같은 말을 할 수있는 여러 가지 방법을 제공합니다. 그러나 assert (length> 0)를 고려하십시오. 따라서 "길이가 0보다 큰지 다시 확인 " 또는 " 길이가 0보다 큰지 확인"으로 변환 할 수 있습니다 . 분명 두 옵션이 작동하는 동안, 나는 아직도 내 선호)
Blake7

4
그러나 다른 해석은“ 길이를 0보다 크게 만드 십시오”입니다. 조금 더 모호합니다.
Luke Maurer

29
영어 동사 "어설 션"과 더 유사합니다
Steve Carter

실제로 "확인"은 "확인하고 확인하지 않으면 변경"으로 해석 될 수 있습니다.
Erik Bongers

14

보세요

C ++의 assert () 예제 프로그램

많은 컴파일러가 assert () 매크로를 제공합니다. assert () 매크로는 매개 변수가 TRUE를 평가하면 TRUE를 리턴하고 FALSE를 평가하면 어떤 조치를 취합니다. 많은 컴파일러가 실패한 assert ()에서 프로그램을 중단합니다. 다른 사람들은 예외를 던질 것입니다

assert () 매크로의 강력한 기능 중 하나는 DEBUG가 정의되지 않은 경우 전처리 기가 코드를 전혀 축소하지 않는다는 것입니다. 개발 과정에서 큰 도움이되며 최종 제품이 출시 될 때 프로그램의 실행 가능한 버전의 크기가 증가하거나 성능이 저하되지 않습니다.

예 :

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3

11
"NDEBUG가 정의 된 경우"가 아니어야합니까?
RichN

2
그 "많은 컴파일러"는 무엇입니까? MSVC와 GCC는이 표준을 모두 준수합니다. 비 호환 컴파일러 : assert가 없습니다. 어설 션이 실패하면 메시지를 인쇄하지 않고 중단합니다. 적절한 NDEBUG 대신 DEBUG를 사용 하시겠습니까?
Steve Jessop

lmao는 물론 java-samples 라는 웹 사이트 입니다.
underscore_d

6

assert () 함수는 프로그램 버그를 진단 할 수 있습니다. C에서는에 정의되어 <assert.h>있고 C ++에서는에 정의되어 <cassert>있습니다. 프로토 타입은

void assert(int expression);

인수 표현식은 변수 또는 C 표현식과 같이 테스트하려는 것이 될 수 있습니다. expression이 TRUE로 평가되면 assert ()는 아무 작업도 수행하지 않습니다. expression이 FALSE로 평가되면 assert ()는 stderr에 오류 메시지를 표시하고 프로그램 실행을 중단합니다.

assert ()를 어떻게 사용합니까? 프로그램 버그 (컴파일 오류와는 구별됨)를 추적하는 데 가장 자주 사용됩니다. 버그는 프로그램 컴파일을 방해하지는 않지만 잘못된 결과를 주거나 부적절하게 실행됩니다 (예 : 잠금). 예를 들어, 작성중인 재무 분석 프로그램이 때때로 잘못된 답변을 제공 할 수 있습니다. 이 변수는 Interest_rate 변수가 음수 값을 취하여 발생하는 것으로 의심되며 절대 발생하지 않아야합니다. 이것을 확인하려면 진술서를 넣으십시오.

주장 (관심 _>> 0); interest_rate가 사용되는 프로그램의 위치에서 변수가 음수가되면 assert () 매크로가 경고합니다. 그런 다음 관련 코드를 검사하여 문제의 원인을 찾을 수 있습니다.

assert () 작동 방식을 보려면 아래 샘플 프로그램을 실행하십시오 . 0이 아닌 값을 입력하면 프로그램이 값을 표시하고 정상적으로 종료됩니다. 0을 입력하면 assert () 매크로가 비정상적인 프로그램 종료를 강제합니다. 표시되는 정확한 오류 메시지는 컴파일러에 따라 다르지만 일반적인 예는 다음과 같습니다.

어설 션 실패 : x, 파일 list19_3.c, 13 행 assert ()가 작동하려면 프로그램을 디버그 모드로 컴파일해야합니다. 디버그 모드 활성화에 대한 정보는 컴파일러 설명서를 참조하십시오 (순간 설명 참조). 나중에 릴리스 모드에서 최종 버전을 컴파일하면 assert () 매크로가 비활성화됩니다.

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

정수 값을 입력하십시오 : 10

10을 입력했습니다.

정수 값을 입력하십시오 : -1

오류 메시지 : 비정상적인 프로그램 종료

오류 메시지는 시스템과 컴파일러에 따라 다를 수 있지만 일반적인 아이디어는 동일합니다.


샘플 프로그램이 assert와 작동하는 방식을 설명했습니다. 주장 자체가 어떻게 작동하지 않습니다. 프로그램을 비정상적으로 종료하는 방법은 무엇입니까? 어떤 종류의 예외가 발생합니까? 어떤 종류? 특별한 신호를 생성합니까? 어떤 신호? 어떤 종류의 C ++ try-catch 메커니즘으로 어설 션을 "잡을"수 있습니까?
Motti Shneor

4

'예외 발생'및 '실행 중지'와 같은 것은 대부분의 컴파일러에 해당 될 수 있지만 모두에게 해당되는 것은 아닙니다. (BTW, 실제로 예외를 던지는 주장 진술이 있습니까?)

c6x와 다른 TI 컴파일러가 사용하는 흥미롭고 약간 다른 어설 션의 의미는 다음과 같습니다. 특정 어설트 명령문을 볼 때 이러한 컴파일러는 해당 명령문의 정보를 사용하여 특정 최적화를 수행합니다. 사악한.

C의 예 :

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

이것은 컴파일러에게 배열이 32 비트 경계에 정렬되어 있음을 알려주므로 컴파일러는 해당 정렬에 대한 특정 명령어를 생성 할 수 있습니다.


1
어설 션이 거짓이고 NDEBUG가 설정되지 않은 경우 어떻게해야합니까? <assert.h>의 assert 버전 인 경우 표준에 따라 메시지를 인쇄하고 중단해야합니다. 분명히 표준은 성명서의 진실에 따라 최적화 할 수 없다고 말하지는 않지만 준수하려면 여전히 거짓이라면 중단해야합니다.
Steve Jessop

1
그들은 표준 행동을 따릅니다
stijn

1

C ++ 11 N3337 표준 초안

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

19.3 주장

1 (표 42)에 설명 된 헤더 <cassert>는 C ++ 프로그램 명제를 문서화하기위한 매크로와 명제 검사를 비활성화하는 메커니즘을 제공합니다.

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

C99 N1256 표준 초안

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2 진단 <assert.h>

1 헤더 <assert.h>는 어설 션 매크로를 정의하고로 NDEBUG정의되지 않은 다른 매크로를 나타냅니다 <assert.h>. 경우 NDEBUG<assert.h를> 포함 된 소스 파일의 시점에서 매크로 이름으로 정의되며, 어설 매크로는 단순히 정의

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

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

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

7.2.1 프로그램 진단

7.2.1.1 주장 매크로

개요

1.

#include <assert.h>
void assert(scalar expression);

기술

2 assert 매크로는 진단 테스트를 프로그램에 넣습니다. void 표현식으로 확장됩니다. 실행될 때 (스칼라 유형을 갖는) expression이 false 인 경우 (즉, 0과 비교) 어설 션 매크로는 실패한 특정 호출에 대한 정보 (인수 텍스트, 소스 파일, 소스 라인 번호 및 엔 클로징 함수의 이름 (후자는 각각 사전 처리 매크로 __FILE____LINE__식별자 __func__) 의 값으로 구현 정의 형식의 표준 오류 스트림에 있습니다. 165) 그런 다음 중단 기능을 호출합니다.

보고

3 어설 션 매크로는 값을 반환하지 않습니다.


1

다른 경우에 assert () 함수를 사용하는 세 가지 주요 이유가 있습니다.

  1. assert () 함수는 주로 디버깅 단계에서 사용되며, 최종 코드에서 방해가 될 수있는 조건을 테스트 할 때마다 printf 문을 사용하여 작성하는 것이 지루합니다.

  2. 대규모 소프트웨어 배포에서 assert는 헤더 파일을 assert () 함수에 연결하기 전에 정의 된 NDEBUG 매크로를 사용하여 컴파일러가 assert 문을 무시하도록하는 데 매우 유용합니다.

  3. assert ()는 함수 또는 일부 코드를 디자인 할 때 유용하며 코드가 작동하지 않는 한계에 대한 아이디어를 얻고 기본적으로 가정에 따라 평가하는 if을 포함 시키려고합니다.


0

평가 한 값이 false 인 경우 프로그램 실행을 중지시키는 기능입니다. 일반적으로 릴리스 설정으로 컴파일 할 때 결과 바이너리로 컴파일되지 않도록 매크로로 둘러싸여 있습니다.

이것은 가정을 테스트하는 데 사용되도록 설계되었습니다. 예를 들면 다음과 같습니다.

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

이상적으로는 잘못된 인수로 함수를 호출하는 것과 같이 프로그램에서 오류를 일으킬 수 있고 segfault가 발생하기 전에 assert를 누르거나 예상대로 작동하지 않는 것입니다.


왜 우리는 if & else를 사용하고 로깅 정보를 추가하지 않습니까?
Asad Khan

1
strcpy에 널 포인터를 전달해서는 안되기 때문입니다. 그것은 일어나지 말아야 할 것들 중 하나입니다. 널 포인터가 전달되면 더 높은 레벨의 무언가가 엉망임을 나타냅니다. 기껏해야 예기치 않은 데이터 값 (정확하지 않거나 널임)으로 인해 문제에서 프로그램을 더 이상 중단해야합니다.
Yacoby

-5

또한이를 사용하여 동적 할당이 성공적인지 확인할 수 있습니다.

코드 예 :

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

비슷하다:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}

3
아니요 . 여기에 new지정하지 않은 경우 할당 실패에 대한 예외가 발생합니다 nothrow. 또한 서식이 이상하고 exit사악합니다.
궤도에서 가벼움 경주

네, 맞아요. 추가하지 않은 것을 잊었습니다. exit 대신에 어떻게 사용할지 알고
싶습니다

1
@Sadikov 다른 사람은 릴리스 모드에서 빌드 할 때 완전히 제거 되지 않은 코드를 사용하여 이러한 오류 조건을 처리 하므로 사전 조건이 충족되지 않아 사용자가 보호되지 않고 정의되지 않은 동작을 할 수 있습니다. 결코 확인하고 붙 잡지 않았습니다 . 릴리스 빌드가 만들어지기 훨씬 전에는 절대로 절대 일어나지 assert()않아야하는 것들을 디버깅하고 스탬핑하기위한 것입니다 .
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.