assert() 에 대하여 .....

air74의 이미지

안녕하세요.

여러 코드에 보면 aasert() 란 함수가 많이 나오더라구요...

디버깅용으로 많이 사용 된다고 하던데.

좀 자세한 정보를 얻고 싶습니다.

조언 부탁드리겠습니다.

감사합니다.

버려진의 이미지

assert( a != 0 ); // something이 0이 아닌지 검사 이런거 할때 씁니다. 일종의 매크로로, 컴파일 과정에서 적절하게(김대기씨의 적절한 운영이 생각나네요) 바뀝니다. assert()안에는 변수에 다른 값을 넣는다던지 하는 것은 좋지 않습니다..

참고로

assert( a != 0 && "a is not zero" );

이런 식으로 써서 간단한 설명을 출력하게 할수도 있습니다.

혹은 이런 것도 있습니다.

if( a >= 0 )
    blah...; return;
else
    blah blah...; return;

assert( 0 ); //여기는 오면 안되는거죠. 여기에 왔는지 검사하는 겁니다.
assert( !"여기 오지 않아야 하는데" ); //이렇게 쓰기도 합니다.
Rica의 이미지

프로그램을 수행하면서 반드시 강제해야 하는 조건이 있을 때 씁니다. 개발 도중에 버그가 생길 수 있으니까, 본 루틴을 수행하기 전에 몇가지 조건들을 검사함으로써 실수를 빨리 발견할 수 있도록 해 줍니다.

구글에서 '방어적 프로그래밍' 을 키워드로 검색해 보세요.

보통 프리프로세서 설정에 의해 디버그 빌드에서는 수행되고 릴리스 빌드에서는 아예 컴파일을 안 합니다. 따라서 assert()의 수행에 따른 성능 저하에 대한 걱정은 안 하셔도 되구요. assert() 안에 사이드 이펙트가 있는 문장을 넣으면 디버그 빌드와 릴리스 빌드의 동작이 달라지는 무시무시한 일을 겪게 됩니다.

doldori의 이미지

예전부터 assert의 효용에 대해서 의문을 갖고 있었는데,
반드시 지켜져야 될 조건이라면 assert를 쓸 것이 아니라
그에 대한 처리까지 하는 것이 좋지 않습니까? 즉

assert(expr);

이 아니라

if (!expr) /* error-handling code */

처럼 쓰는 것이 바람직하다는 거죠. 실행 중에 abort()를 하는 것은 사용자
입장에서는 욕나오는 일일 테니까요.
"assert를 쓰는 것은 연습에서는 중무장하다가 실전에서는 맨몸으로 나가는
것과 같다"는 말을 들었는데 정말 맞는 말이라고 생각합니다.

익명 사용자의 이미지

처리가 필요하다가 판단할 수 없는 경우 즉, code writer의 판단으로는 논리적으로 올 수 없는 control flow를 검사할 때 assert를 사용하는 것으로 알고 있습니다.
말씀하신 것 과 같은 처리가 필요하다가 판단이 되는 경우에는 어떻게든 처리해야 맞지요.
그런 처리를 다 하고도 남는 control flow가 있습니다.
분명 flow는 남는데 내 판단으로는 이 flow를 타는 일은 없을 것 같다.
그런 경우에 assert로 code co-writer에게 이런 flow를 알리고, 어쩌면 놓쳤을지도 모를 case를 대비합니다.
대충 이런식이 아닐런지요?

seoleda의 이미지

조건에 일치하지 않는 경우, 딱히 처리할 수 있는 방법이 항상 존재하는게 아니잖아요.

일반적으로 조건이 안맞는다면 처리하는 방법이 다음과 같이

1. 가만히 있는다.
2. 프로그램을 종료한다.
3. 데이타를 다시 받는다.

머 이정도일 것 같은데, assert를 사용하면 릴리즈 모드에서는 1번으로 되겠고, 디버그 모드에선 2번으로 되겠지요. 3번과 같이 처리할 경우에는 if( expr)을 사용해야 겠지요.

assert는 릴리즈모드에선 코드가 사라지는 것이 장점이자 단점이지만, assert문을 사용함으로써 틀린부분을 정확히 짚어낼 수 있다는 것만으로도, 충분히 가치가 있다고 생각합니다.

bugiii의 이미지

doldori wrote:
예전부터 assert의 효용에 대해서 의문을 갖고 있었는데,
반드시 지켜져야 될 조건이라면 assert를 쓸 것이 아니라
그에 대한 처리까지 하는 것이 좋지 않습니까? 즉

assert(expr);

이 아니라

if (!expr) /* error-handling code */

처럼 쓰는 것이 바람직하다는 거죠. 실행 중에 abort()를 하는 것은 사용자
입장에서는 욕나오는 일일 테니까요.
"assert를 쓰는 것은 연습에서는 중무장하다가 실전에서는 맨몸으로 나가는
것과 같다"는 말을 들었는데 정말 맞는 말이라고 생각합니다.

assert는 디버깅용에만 써야 하고, 디버깅 코드만 기술해야 하고, 절대 일어나서는 안되는 알고리즘상의 버그를 찾는 곳에 사용한다면 문제없다고 생각합니다.

최종 릴리즈 시에는 제거되는 코드들이므로 assert 때문에 abort 가 호출되지는 않겠지만 앞의 조건을 만족한다면 디버깅은 편하고 릴리즈는 탄탄하면서 빠른 코드가 생길 것이라고 생각합니다.

어쩔 수 없이 일어날 수밖에 없는 사용자의 입력 에러나 데이터 에러는 assert 로 해서는 절대 안되고 정상적인 에러 처리 루틴으로 처리해야 하는 것이 당연하다고 생각합니다.

jj의 이미지

bugiii wrote:
doldori wrote:
예전부터 assert의 효용에 대해서 의문을 갖고 있었는데,
반드시 지켜져야 될 조건이라면 assert를 쓸 것이 아니라
그에 대한 처리까지 하는 것이 좋지 않습니까? 즉

assert(expr);

이 아니라

if (!expr) /* error-handling code */

처럼 쓰는 것이 바람직하다는 거죠. 실행 중에 abort()를 하는 것은 사용자
입장에서는 욕나오는 일일 테니까요.
"assert를 쓰는 것은 연습에서는 중무장하다가 실전에서는 맨몸으로 나가는
것과 같다"는 말을 들었는데 정말 맞는 말이라고 생각합니다.

assert는 디버깅용에만 써야 하고, 디버깅 코드만 기술해야 하고, 절대 일어나서는 안되는 알고리즘상의 버그를 찾는 곳에 사용한다면 문제없다고 생각합니다.

최종 릴리즈 시에는 제거되는 코드들이므로 assert 때문에 abort 가 호출되지는 않겠지만 앞의 조건을 만족한다면 디버깅은 편하고 릴리즈는 탄탄하면서 빠른 코드가 생길 것이라고 생각합니다.

어쩔 수 없이 일어날 수밖에 없는 사용자의 입력 에러나 데이터 에러는 assert 로 해서는 절대 안되고 정상적인 에러 처리 루틴으로 처리해야 하는 것이 당연하다고 생각합니다.

좋은 말씀 많이 해주셨는데요, 덧붙이면 assert-fail은 개발상의 오류에 의해서 생기는거지 사용자 입력에 따라서 생기면 잘못사용된된 assert죠, 이럴땐 예외상황을 처리하는 루틴이 필요하겠죠.

--
Life is short. damn short...

pynoos의 이미지

제가 사용하는 assert를 해야할지, 에러처리를 해야할지에 대한 기준은 이렇습니다.

생각나는대로 씁니다.

  1. 외부 입력(소켓, 키보드, 파일)으로부터 저장된 변수는 에러처리.
  2. 1 번이 아닌 설계상 값의 반드시 그 값이 어떠해야한다면 (NULL이 아니라던지, 0 보다 크거나 같아야한다던지) assert.
  3. enum 값이 넘어다니는 곳은 assert.
  4. if else, if else chain 에서 맨마지막 else 에서 필요한 경우 assert(0)
  5. enum을 switch 로 해결할 때, default 에서 필요한 경우 assert(0)
  6. 리소스(메모리, 파일 디스크립터 등)를 해제할 경우 되도록 assert 로 해제할 리소스가 유효한지 확인. 확실하게 두번 해제하는 경우는 없도록 함.
무엇보다 가장 중요한 기준은 1,2번입니다.[/]
yhjj777의 이미지

assert 때문에 요즘 피보는중이라 그냥 지나칠수가 없네요. 코드에 정말 많이assert를 집어넣는 스타일인데요. 충분한 테스트를 거치지않은채 클로즈 베타를 시작했더니 하루에 대략 3~4번 assert에 걸려서 다운이 되더군요.

다운되면 바로 띄워줘야지되서 그럴때마다 임시 땜빵으로 assert 를 빼고 예외 처리를 하는 코드를 넣곤 하는데요. 이런 코드가 대부분 들어가서는 안될 값이 들어갔거나 널 포인터들이라 난감합니다.

assert를 넣고 돌리자니 완벽하게 그 에러가 잡히지않는이상 또 다운될게 분명하고, assert를 뺴자니 잡아야될 에러인데 잡지않고 임시 떔빵 처리를 해야되는게 맘에 걸리고.. 이런게 누적되면 나중에 버그 잡기가 더욱 힘들어지지않을까 싶구요. 버그 잡을 시간이 충분하다면 잡고 넘어갈테지만.. 쩝..

mirheekl의 이미지

엔드유저가 디버그버전 바이너리를 받는 경우는 드무니 서버 사이드로 생각이 되는데.. 맞는지요?

그런경우 매일 빌드를 돌리면서 심볼 등 디버그 정보를 특정 장소에 누적시켜 쌓아놓고, 예외발생시 크래시덤프 저장후 자동 재시작을 시킵니다. 그리고 정해진 유지보수 시간에 서버를 자동으로 업데이트하고요. 한번 자동화되면 개발자들은 크래시덤프들을 분석해서 버그를 수정하면 됩니다. 이렇게 해두면 여러 개발자가 각각 다른 예외를 들여다볼 수 있게 되지요. 이렇게 하는게 일반적인 방법입니다.

제가 보기엔 현재 방법에 별 문제가 없는 것 같네요. 다만 자동화(크래시덤핑, 업데이트, 재시작 등등)를 추가적으로 해두셔야 할것 같고.. 디버깅에 충분한 인력이 할당돼있지 않다면 회사에 인력충원 건의를 하셔야 합니다. 안정적인 회사일수록 이런 부분이 견고하게 잘 되어 있습니다. 매번 반복되는 고생을 아무 대처 없이 그냥 기존 인력만 갈아넣어서 해결하려는 회사는 가급적 피하시는 것이..

예외처리 없이 assert만 빼시면 걱정하시는대로 전혀 엉뚱한곳에서 일이 터지게 될겁니다. 그 방법은 절대 쓰지 마셔야..

--

mirheekl의 이미지

개인적으로는 체크 코드는 꼭 넣고 싶은데 코드 리뷰어가 그걸 마음에 들어하지 않을 때 사용하고 있습니다. 코드상으로 봐선 해당 예외가 절대 발생할 가능성이 없어 보일 때 주로 이런 일이 발생합니다. 예전 소스를 보니 실제 프로젝트에서도 그런 용도로 대부분 사용되었더군요.

--

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.