C言語の「assert.h」を使ったサンプルプログラムです。
たまに見かけるコードなのですが、自分では今までに使った事が無くて、今回初めて使ってみました。
- assert() 条件の検証
CU_ASSERT()と同じような機能なのですが、偽の場合にプログラムをABORTしてしまうところが異なります。
目次
サンプルコード
[assert.c]
/****************************************************************//**
* \file assert.c
*
* \brief assert()関数のサンプルアプリケーション
*
* - 文字コード・改行コード
* - 文字コードは UTF-8(BOM無し)
* - 改行コードは LF
*
* \author tomyama Oct 2022
* \version $Revision$
* \date $Date$
********************************************************************/#include <stdio.h>
//#define NDEBUG
//#ifdef MYDEBUG /* Not RELEASE */
// #undef NDEBUG
//#endif
#include <assert.h> /* assert() */
#ifndef NDEBUG
#include <errno.h> /* errno */
#include <string.h> /* strerror() */
#include <signal.h> /* signal() */
#endif /* ! NDEBUG */
/*+++++++[ 定数定義 ]+++++++++++++++++++++++++++++++++++++*/#ifdef NDEBUG
#define preparingAssert()
#endif /* NDEBUG */
/*+++++++[ 型定義 ]+++++++++++++++++++++++++++++++++++++++*/
/*+++++++[ 関数プロトタイプ ]+++++++++++++++++++++++++++++*/static void cleanup( void );
#ifndef NDEBUG
static int preparingAssert( void );
static void sighdl_abort( int signum );
#endif /* ! NDEBUG */
/*+++++++[ 変数定義 ]+++++++++++++++++++++++++++++++++++++*/
/*+++++++[ 関数定義 ]+++++++++++++++++++++++++++++++++++++*/int main( int argc, char *argv[] )
{
preparingAssert();assert( argc == 1 ); /* 診断コード: 引数が指定されていない事 */
printf( "%s(): 正常系の終了パス: assert()が効いた時にはここは通らない\n", __func__ );
cleanup();
return 0;
}
static void cleanup( void )
{
/* 何かする */
printf( "%s(): 何かする\n", __func__ );
}
#ifndef NDEBUG
static int preparingAssert( void )
{
/* SIGABRTシグナルを受信した時の動作を変更する */
if( signal( SIGABRT, sighdl_abort ) == SIG_ERR ){
fprintf( stderr, "%s(): error: signal(): <%d>%s\n",
__func__, errno, strerror( errno ) );
return errno;
}
return 0;
}
/*************************************************
* シグナルハンドラ << SIGABRT >>
*************************************************/static void sighdl_abort( int signum )
{
printf( "%s(): abnormal end: abort !!!\n", __func__ );
cleanup();
return;
}
#endif /* ! NDEBUG */
実行例
Windows 10, Visual Studio 2022, x86 Native Tools Command Prompt
デバッグ用にコンパイル
>set CFLAGS=/nologo /source-charset:utf-8 /execution-charset:shift_jis
>cl %CFLAGS% /Fe:assert_msvc assert.c
assert.c
>
>assert_msvc.exe & echo exit_status: %ERRORLEVEL%
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
>
>assert_msvc.exe 123 & echo exit_status: %ERRORLEVEL%
Assertion failed: argc == 1, file assert.c, line 54
sighdl_abort(): abnormal end: abort !!!
cleanup(): 何かする
exit_status: 0
>
- WindowsのVisual CではABORTしてもステータスは0のまま。他のプラットフォームとは異なり異常終了扱いにはならない。
リリース用にコンパイル
- NDEBUGマクロを定義してassert()関連のコードを除去
>cl %CFLAGS% /Fe:assert_msvc assert.c /DNDEBUG
assert.c
>
>assert_msvc.exe & echo exit_status: %ERRORLEVEL%
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
>
>assert_msvc.exe 123 & echo exit_status: %ERRORLEVEL%
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
>
- リリース用のプログラムはどちらも同じ結果になる。( ≒ assert()文が除去できている。)
CentOS Stream 9, gcc (GCC) 11.3.1
デバッグ用にコンパイル
$ gcc -Wall -O2 -o assert_centos9 assert.c
$
$ ./assert_centos9 ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_centos9 123 ; echo "exit_status: $?"
assert_centos9: assert.c:54: main: Assertion `argc == 1' failed.
sighdl_abort(): abnormal end: abort !!!
cleanup(): 何かする
中止 (コアダンプ)
exit_status: 134
$
リリース用にコンパイル
- NDEBUGマクロを定義してassert()関連のコードを除去
$ gcc -Wall -O2 -o assert_centos9 assert.c -DNDEBUG
$
$ ./assert_centos9 ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_centos9 123 ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
- リリース用のプログラムはどちらも同じ結果になる。( ≒ assert()文が除去できている。)
Cygwin 3.3.6-1, gcc (GCC) 11.3.0
デバッグ用にコンパイル
$ gcc -Wall -O2 -o assert_cygwin assert.c
$
$ ./assert_cygwin.exe ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_cygwin.exe 123 ; echo "exit_status: $?"
assertion "argc == 1" failed: file "assert.c", line 25, function: main
sighdl_abort(): abnormal end: abort !!!
cleanup(): 何かする
Aborted
exit_status: 134
$
リリース用にコンパイル
- NDEBUGマクロを定義してassert()関連のコードを除去
$ gcc -Wall -O2 -o assert_cygwin assert.c -DNDEBUG
$
$ ./assert_cygwin.exe ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_cygwin.exe 123 ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
- リリース用のプログラムはどちらも同じ結果になる。( ≒ assert()文が除去できている。)
Android, Termux 0.118.0, clang 15.0.2
デバッグ用にコンパイル
$ gcc -Wall -O2 -o assert_termux assert.c
$
$ ./assert_termux ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_termux 123 ; echo "exit_status: $?"
assert.c:25: int main(int, char **): assertion "argc == 1" failed
sighdl_abort(): abnormal end: abort !!!
cleanup(): 何かする
Aborted
exit_status: 134
$
リリース用にコンパイル
- NDEBUGマクロを定義してassert()関連のコードを除去
$ gcc -Wall -O2 -o assert_termux assert.c -DNDEBUG
$
$ ./assert_termux ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
$ ./assert_termux 123 ; echo "exit_status: $?"
main(): 正常系の終了パス: assert()が効いた時にはここは通らない
cleanup(): 何かする
exit_status: 0
$
- リリース用のプログラムはどちらも同じ結果になる。( ≒ assert()文が除去できている。)