{"id":23714389,"url":"https://github.com/gpakosz/ppk_assert","last_synced_at":"2026-03-06T02:40:37.934Z","repository":{"id":11906286,"uuid":"14470522","full_name":"gpakosz/PPK_ASSERT","owner":"gpakosz","description":"PPK_ASSERT is an orthodox drop-in \u0026 self-contained C++ assertion library ⚠️","archived":false,"fork":false,"pushed_at":"2021-10-16T07:31:37.000Z","size":350,"stargazers_count":203,"open_issues_count":2,"forks_count":16,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-11-11T00:02:29.131Z","etag":null,"topics":["assert","cpp","debug"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gpakosz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"gpakosz"}},"created_at":"2013-11-17T16:44:14.000Z","updated_at":"2024-10-05T20:16:49.000Z","dependencies_parsed_at":"2022-09-07T02:10:23.402Z","dependency_job_id":null,"html_url":"https://github.com/gpakosz/PPK_ASSERT","commit_stats":null,"previous_names":["gpakosz/assert"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpakosz%2FPPK_ASSERT","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpakosz%2FPPK_ASSERT/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpakosz%2FPPK_ASSERT/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gpakosz%2FPPK_ASSERT/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gpakosz","download_url":"https://codeload.github.com/gpakosz/PPK_ASSERT/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231908207,"owners_count":18444268,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assert","cpp","debug"],"created_at":"2024-12-30T20:19:24.805Z","updated_at":"2026-03-06T02:40:37.877Z","avatar_url":"https://github.com/gpakosz.png","language":"C++","readme":"# Assert: a cross platform drop-in + self-contained C++ assertion library\n[![Build Status](https://travis-ci.org/gpakosz/PPK_ASSERT.png?branch=master)](https://travis-ci.org/gpakosz/PPK_ASSERT)\n\n## TLDR\n\n    #include \u003cboost/assert.hpp\u003e\n    #include \u003csstream\u003e\n\n    int main()\n    {\n      float min = 0.0f;\n      float max = 1.0f;\n      float v = 2.0f;\n      BOOST_ASSERT_MSG(v \u003e min \u0026\u0026 v \u003c max, static_cast\u003cstd::ostringstream\u0026\u003e(std::ostringstream().flush() \u003c\u003c \\\n                      \"invalid value: \" \u003c\u003c v \u003c\u003c \", must be between \" \u003c\u003c min \u003c\u003c \" and \" \u003c\u003c max).str().c_str());\n      return 0;\n    }\n\n**vs**\n\n    #include \u003cppk_assert.h\u003e\n\n    int main()\n    {\n      float min = 0.0f;\n      float max = 1.0f;\n      float v = 2.0f;\n      PPK_ASSERT(v \u003e min \u0026\u0026 v \u003c max, \"invalid value: %f, must be between %f and %f\", v, min, max);\n\n      return 0;\n    }\n\nNow which do you prefer? I know which I prefer.\n\nJust drop `ppk_assert.h` and `ppk_assert.cpp` into your build and get\nstarted. (see also [customizing compilation])\n\n[customizing compilation]: #customizing-compilation\n\n## Why?\n\nIt all started with the need to provide a meaningful message when assertions\nfire. There is a well-known hack with standard `assert` to inject a message next\nto the expression being tested:\n\n    assert(expression \u0026\u0026 \"message\");\n\nBut it's limited to string literals. I wanted improve on `assert()` by\nproviding the following features:\n\n- being able to format a message that would also contain the values for\n  different variables around the point of failure\n- having different levels of severity\n- being able to selectively ignore assertions while debugging\n- being able to break into the debugger at the exact point an assertion fires\n  (that is in your own source code, instead of somewhere deep inside `assert`\n  implementation)\n- no memory allocation\n- no unused variables warning when assertions are disabled\n\n--------------------------------------------------------------------------------\n\n## What?\n\nThe library is designed to be lightweight would you decide to keep assertions\nenabled even in release builds (`#define PPK_ASSERT_ENABLED 1`).\n\nBy default, each assertion eats up `sizeof(bool)` of stack, used to keep track\nwhether the assertion should be ignored for the remaining lifetime of the\nprogram. You can disable this feature (see [customizing compilation]).\n\n### Message Formatting\n\nThe library provides `printf` like formatting:\n\n    PPK_ASSERT(expression);\n    PPK_ASSERT(expression, message, ...);\n\nE.g:\n\n    PPK_ASSERT(validate(v, min, max), \"invalid value: %f, must be between %f and %f\", v, min, max);\n\n### Levels Of Severity\n\nThis library defines different levels of severity:\n\n- `PPK_ASSERT_WARNING`\n- `PPK_ASSERT_DEBUG`\n- `PPK_ASSERT_ERROR`\n- `PPK_ASSERT_FATAL`\n\nWhen you use `PPK_ASSERT`, the severity level is determined by the\n`PPK_ASSERT_DEFAULT_LEVEL` preprocessor token.\n\nYou can also add your own additional severity levels by using:\n\n    PPK_ASSERT_CUSTOM(level, expression);\n    PPK_ASSERT_CUSTOM(level, expression, message, ...);\n\n### Default Assertion Handler\n\nThe default handler associates a predefined behavior to each of the different\nlevels:\n\n- `WARNING \u003c= level \u003c DEBUG`: print the assertion message to `stderr`\n- `DEBUG \u003c= level \u003c ERROR`: print the assertion message to `stderr` and prompt\n   the user for action (disabled by default on iOS and Android)\n- `ERROR \u003c= level \u003c FATAL`: throw an `AssertionException`\n- `FATAL \u003c level`: abort the program\n\nIf you know you're going to launch your program from within a login shell\nsession on iOS or Android (e.g. through SSH), define the\n`PPK_ASSERT_DEFAULT_HANDLER_STDIN` preprocessor token.\n\nWhen prompting for user action, the default handler prints the following\nmessage on `stderr`:\n\n    `Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:`\n\nAnd waits for input on `stdin`:\n\n- Ignore: ignore the current assertion\n- Ignore Forever: remember the file and line where the assertion fired and\n  ignore it for the remaining execution of the program\n- Ignore All: ignore all remaining assertions (all files and lines)\n- Debug: break into the debugger if attached, otherwise `abort()` (on Windows,\n  the system will prompt the user to attach a debugger)\n- Abort: call `abort()` immediately\n\nUnder the Windows platform, the default handler also uses `OutputDebugString`\nand in the case of a GUI application allocates a console upon encountering the\nfirst failed assertion.\n\nUnder the Android platform, the default handler also sends log messages to the\nin-kernel log buffer, which can later be accessed through the `logcat` utility.\n\nThe default handler supports optional logging to a file (suggested by\n[@nothings]):\n\n- `#define PPK_ASSERT_LOG_FILE \"/tmp/assert.txt\"`\n- to truncate the log file upon each program invocation, `#define\n  PPK_ASSERT_LOG_FILE_TRUNCATE`\n\n[@nothings]: https://twitter.com/nothings\n\n### Providing Your Own Handler\n\nIf you want to change the default behavior, e.g. by opening a dialog box or\nlogging assertions to a database, you can provide a custom handler with the\nfollowing signature:\n\n    typedef AssertAction::AssertAction (*AssertHandler)(const char* file,\n                                                        int line,\n                                                        const char* function,\n                                                        const char* expression,\n                                                        int level,\n                                                        const char* message);\n\nYour handler will be called with the proper information filled and needs to\nreturn the action to be performed:\n\n    PPK_ASSERT_ACTION_NONE,\n    PPK_ASSERT_ACTION_ABORT,\n    PPK_ASSERT_ACTION_BREAK,\n    PPK_ASSERT_ACTION_IGNORE,\n    PPK_ASSERT_ACTION_IGNORE_LINE,\n    PPK_ASSERT_ACTION_IGNORE_ALL,\n    PPK_ASSERT_ACTION_THROW\n\nTo install your custom handler, call:\n\n    ppk::assert::implementation::setAssertHandler(customHandler);\n\n### Unused Return Values\n\nThe library provides `PPK_ASSERT_USED` that fires an assertion when an unused\nreturn value reaches end of scope:\n\n    PPK_ASSERT_USED(int) foo();\n\nWhen calling `foo()`,\n\n    {\n      foo();\n\n      // ...\n\n      bar();\n\n      // ...\n\n      baz();\n    } \u003c- assertion fires, caused by unused `foo()` return value reaching end of scope\n\nJust like `PPK_ASSERT`, `PPK_ASSERT_USED` uses\n`PPK_ASSERT_DEFAULT_LEVEL`. If you want more control on the severity, use one\nof:\n\n    PPK_ASSERT_USED_WARNING(type)\n    PPK_ASSERT_USED_DEBUG(type)\n    PPK_ASSERT_USED_ERROR(type)\n    PPK_ASSERT_USED_FATAL(type)\n    PPK_ASSERT_USED_CUSTOM(level, type)\n\nArguably, unused return values are better of detected by the compiler. For\ninstance GCC and Clang allow you to mark function with attributes:\n\n    __attribute__((warn_unused_result)) int foo();\n\nWhich will emit the following warning in case the return value is not used:\n\n    warning: ignoring return value of function declared with warn_unused_result attribute [-Wunused-result]\n\nHowever there is no MSVC++ equivalent. Well there is `__checkReturn` but it\nsupposedly only have effect when running static code analysis and I failed to\nmake it work with Visual Studio 2013 Express. Wrapping `PPK_ASSERT_USED`\naround a return type is a cheap way to debug a program where you suspect a\nfunction return value is being ignored and shouldn't have been.\n\n### Compile-time assertions\n\n    PPK_STATIC_ASSERT(expression)\n    PPK_STATIC_ASSERT(expression, message)\n\nIn case of compile-time assertions, the message must be a string literal and\ncan't be formated like with run-time assertions, e.g:\n\n    PPK_STATIC_ASSERT(sizeof(foo) \u003e sizeof(bar), \"size mismatch\");\n\nWhen compiled with a C++11 capable compiler, `PPK_STATIC_ASSERT` defers to\n`static_assert`. Contrary to `static_assert`, it's possible to use\n`PPK_STATIC_ASSERT` without a message.\n\n## Customizing compilation\n\nIn order to use `PPK_ASSERT` in your own project, you just have to bring in\nthe two `ppk_assert.h` and `ppk_assert.cpp` files. **It's that simple**.\n\nYou can customize the library's behavior by defining the following macros:\n\n- `#define PPK_ASSERT_ENABLED 1` or `#define PPK_ASSERT_ENABLED 0`: enable\n  or disable assertions, otherwise enabled state is based on `NDEBUG`\n  preprocessor token being defined\n- `PPK_ASSERT_DEFAULT_LEVEL`: default level to use when using the\n  `PPK_ASSERT` macro\n- `PPK_ASSERT_DISABLE_STL`: `AssertionException` won't inherit from\n  `std::exception`\n- `PPK_ASSERT_DISABLE_EXCEPTIONS`: the library won't throw exceptions on\n  `ERROR` level but instead rely on a user provided `throwException` function\n  that will likely `abort()` the program\n- `PPK_ASSERT_MESSAGE_BUFFER_SIZE`\n- `PPK_ASSERT_DISABLE_IGNORE_LINE`: disables the injection of a `static bool`\n  variable used to keep track whether the assertion should be ignored for the\n  remaining lifetime of the program\n- `PPK_ASSERT_DEBUG_BREAK`: lets you redefine programmatic breakpoints\n\nIf you want to use a different prefix, provide your own header that includes\n`ppk_assert.h` and define the following:\n\n    // custom prefix\n    #define ASSERT                PPK_ASSERT\n    #define ASSERT_WARNING        PPK_ASSERT_WARNING\n    #define ASSERT_DEBUG          PPK_ASSERT_DEBUG\n    #define ASSERT_ERROR          PPK_ASSERT_ERROR\n    #define ASSERT_FATAL          PPK_ASSERT_FATAL\n    #define ASSERT_CUSTOM         PPK_ASSERT_CUSTOM\n    #define ASSERT_USED           PPK_ASSERT_USED\n    #define ASSERT_USED_WARNING   PPK_ASSERT_USED_WARNING\n    #define ASSERT_USED_DEBUG     PPK_ASSERT_USED_DEBUG\n    #define ASSERT_USED_ERROR     PPK_ASSERT_USED_ERROR\n    #define ASSERT_USED_FATAL     PPK_ASSERT_USED_FATAL\n    #define ASSERT_USED_CUSTOM    PPK_ASSERT_USED_CUSTOM\n\n\n### Compiling for Windows\n\nThere is a Visual Studio 2015 solution in the `_win-vs14/` folder.\n\n### Compiling for Linux or Mac\n\nThere is a GNU Make 3.81 `MakeFile` in the `_gnu-make/` folder:\n\n    $ make -j -C _gnu-make/\n\n### Compiling for Mac\n\nSee above if you want to compile from command line. Otherwise there is an Xcode\nproject located in the `_mac-xcode/` folder.\n\n### Compiling for iOS\n\nThere is an Xcode project located in the `_ios-xcode/` folder.\n\nIf you prefer compiling from command line and deploying to a jailbroken device\nthrough SSH, use:\n\n    $ make -j -C _gnu-make/ binsubdir=ios CXX=\"$(xcrun --sdk iphoneos --find clang++) -isysroot $(xcrun --sdk iphoneos --show-sdk-path) -arch armv7 -arch armv7s -arch arm64\" CPPFLAGS=-DPPK_ASSERT_DEFAULT_HANDLER_STDIN postbuild=\"codesign -s 'iPhone Developer'\"\n\n### Compiling for Android\n\nYou will have to install the Android NDK, and point the `$NDK_ROOT` environment\nvariable to the NDK path: e.g. `export NDK_ROOT=/opt/android-ndk` (without a\ntrailing `/` character).\n\nNext, the easy way is to make a standalone Android toolchain with the following\ncommand:\n\n    $ $NDK_ROOT/build/tools/make_standalone_toolchain.py --arch=arm --install-dir=/tmp/android-toolchain\n\nNow you can compile the self test and self benchmark programs by running:\n\n    $ make -j -C _gnu-make/ binsubdir=android CXX=/tmp/android-toolchain/bin/clang++ LDFLAGS='-llog' CPPFLAGS=-DPPK_ASSERT_DEFAULT_HANDLER_STDIN\n\n--------------------------------------------------------------------------------\n\n## Credits Where It's Due:\n\nThis assertion library has been lingering in my pet codebase for years. It has\ngreatly been inspired by [Andrei Alexandrescu][@incomputable]'s CUJ articles:\n\n- [Assertions][assertions]\n- [Enhancing Assertions][enhancing-assertions]\n\n[assertions]: http://www.drdobbs.com/assertions/184403861\n[enhancing-assertions]: http://www.drdobbs.com/cpp/enhancing-assertions/184403745\n[@incomputable]: https://twitter.com/incomputable\n\nI learnt the `PPK_UNUSED` trick from [Branimir Karadžić][@bkaradzic].\n\nFinally, [`__VA_NARG__` has been invented by Laurent Deniau][__VA_NARG__].\n\n[@bkaradzic]: https://twitter.com/bkaradzic\n[__VA_NARG__]: https://groups.google.com/d/msg/comp.std.c/d-6Mj5Lko_s/5R6bMWTEbzQJ\n\n\n--------------------------------------------------------------------------------\n\nIf you find this library useful and decide to use it in your own projects please\ndrop me a line [@gpakosz].\n\n[@gpakosz]: https://twitter.com/gpakosz\n","funding_links":["https://github.com/sponsors/gpakosz"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpakosz%2Fppk_assert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgpakosz%2Fppk_assert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgpakosz%2Fppk_assert/lists"}