|
| 1 | +# `dbg(…)` |
| 2 | + |
| 3 | +[](https://travis-ci.org/sharkdp/dbg-macro) [](https://ci.appveyor.com/project/sharkdp/dbg-macro) [](https://repl.it/@sharkdp/dbg-macro-demo) [](dbg.h) |
| 4 | + |
| 5 | +*A macro for `printf`-style debugging fans.* |
| 6 | + |
| 7 | +Debuggers are great. But sometimes you just don't have the time or patience to set |
| 8 | +up everything correctly and just want a quick way to inspect some values at runtime. |
| 9 | + |
| 10 | +This projects provides a [single header file](dbg.h) with a `dbg(…)` |
| 11 | +macro that can be used in all circumstances where you would typically write |
| 12 | +`printf("…", …)` or `std::cout << …`. But it comes with a few extras. |
| 13 | + |
| 14 | +## Examples |
| 15 | + |
| 16 | +``` c++ |
| 17 | +#include <vector> |
| 18 | +#include <dbg.h> |
| 19 | + |
| 20 | +// You can use "dbg(..)" in expressions: |
| 21 | +int factorial(int n) { |
| 22 | + if (dbg(n <= 1)) { |
| 23 | + return dbg(1); |
| 24 | + } else { |
| 25 | + return dbg(n * factorial(n - 1)); |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +int main() { |
| 30 | + std::string message = "hello"; |
| 31 | + dbg(message); // [example.cpp:15 (main)] message = "hello" (std::string) |
| 32 | + |
| 33 | + const int a = 2; |
| 34 | + const int b = dbg(3 * a) + 1; // [example.cpp:18 (main)] 3 * a = 6 (int) |
| 35 | + |
| 36 | + std::vector<int> numbers{b, 13, 42}; |
| 37 | + dbg(numbers); // [example.cpp:21 (main)] numbers = {7, 13, 42} (size: 3) (std::vector<int>) |
| 38 | + |
| 39 | + dbg("this line is executed"); // [example.cpp:23 (main)] this line is executed |
| 40 | + |
| 41 | + factorial(4); |
| 42 | + |
| 43 | + return 0; |
| 44 | +} |
| 45 | +``` |
| 46 | +
|
| 47 | +The code above produces this output ([try it yourself](https://repl.it/@sharkdp/dbg-macro-demo)): |
| 48 | +
|
| 49 | + |
| 50 | +
|
| 51 | +## Features |
| 52 | +
|
| 53 | + * Easy to read, colorized output (colors auto-disable when the output is not an interactive terminal) |
| 54 | + * Prints file name, line number, function name and the original expression |
| 55 | + * Adds type information for the printed-out value |
| 56 | + * Specialized pretty-printers for containers, pointers, string literals, enums, `std::optional`, etc. |
| 57 | + * Can be used inside expressions (passing through the original value) |
| 58 | + * The `dbg.h` header issues a compiler warning when included (so you don't forget to remove it). |
| 59 | + * Compatible and tested with C++11, C++14 and C++17. |
| 60 | +
|
| 61 | +## Installation |
| 62 | +
|
| 63 | +To make this practical, the `dbg.h` header should to be readily available from all kinds of different |
| 64 | +places and in all kinds of environments. The quick & dirty way is to actually copy the header file |
| 65 | +to `/usr/include` or to clone the repository and symlink `dbg.h` to `/usr/include/dbg.h`. |
| 66 | +``` bash |
| 67 | +git clone https://github.com/sharkdp/dbg-macro |
| 68 | +sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h |
| 69 | +``` |
| 70 | +If you don't want to make untracked changes to your filesystem, check below if there is a package for |
| 71 | +your operating system or package manager. |
| 72 | + |
| 73 | +### On Arch Linux |
| 74 | + |
| 75 | +You can install [`dbg-macro` from the AUR](https://aur.archlinux.org/packages/dbg-macro/): |
| 76 | +``` bash |
| 77 | +yay -S dbg-macro |
| 78 | +``` |
| 79 | + |
| 80 | +### With vcpkg |
| 81 | + |
| 82 | +You can install the [`dbg-macro` port](https://github.com/microsoft/vcpkg/tree/master/ports/dbg-macro) via: |
| 83 | +``` bash |
| 84 | +vcpkg install dbg-macro |
| 85 | +``` |
| 86 | + |
| 87 | +## Configuration |
| 88 | + |
| 89 | +* Set the `DBG_MACRO_DISABLE` flag to disable the `dbg(…)` macro (i.e. to make it a no-op). |
| 90 | +* Set the `DBG_MACRO_NO_WARNING` flag to disable the *"'dbg.h' header is included in your code base"* warnings. |
| 91 | + |
| 92 | +## Advanced features |
| 93 | + |
| 94 | +### Hexadecimal, octal and binary format |
| 95 | + |
| 96 | +If you want to format integers in hexadecimal, octal or binary representation, you can |
| 97 | +simply wrap them in `dbg::hex(…)`, `dbg::oct(…)` or `dbg::bin(…)`: |
| 98 | +```c++ |
| 99 | +const uint32_t secret = 12648430; |
| 100 | +dbg(dbg::hex(secret)); |
| 101 | +``` |
| 102 | +
|
| 103 | +### Printing type names |
| 104 | +
|
| 105 | +`dbg(…)` already prints the type for each value in parenthesis (see screenshot above). But |
| 106 | +sometimes you just want to print a type (maybe because you don't have a value for that type). |
| 107 | +In this case, you can use the `dbg::type<T>()` helper to pretty-print a given type `T`. |
| 108 | +For example: |
| 109 | +```c++ |
| 110 | +template <typename T> |
| 111 | +void my_function_template() { |
| 112 | + using MyDependentType = typename std::remove_reference<T>::type&&; |
| 113 | + dbg(dbg::type<MyDependentType>()); |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +### Print the current time |
| 118 | + |
| 119 | +To print a timestamp, you can use the `dbg::time()` helper: |
| 120 | +```c++ |
| 121 | +dbg(dbg::time()); |
| 122 | +``` |
| 123 | +
|
| 124 | +### Customization |
| 125 | +
|
| 126 | +If you want `dbg(…)` to work for your custom datatype, you can simply overload `operator<<` for |
| 127 | +`std::ostream&`: |
| 128 | +```c++ |
| 129 | +std::ostream& operator<<(std::ostream& out, const user_defined_type& v) { |
| 130 | + out << "…"; |
| 131 | + return out; |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +If you want to modify the type name that is printed by `dbg(…)`, you can add a custom |
| 136 | +`get_type_name` overload: |
| 137 | +```c++ |
| 138 | +// Customization point for type information |
| 139 | +namespace dbg { |
| 140 | + std::string get_type_name(type_tag<bool>) { |
| 141 | + return "truth value"; |
| 142 | + } |
| 143 | +} |
| 144 | +``` |
| 145 | +
|
| 146 | +## Development |
| 147 | +
|
| 148 | +If you want to contribute to `dbg-macro`, here is how you can build the tests and demos: |
| 149 | +
|
| 150 | +Make sure that the submodule(s) are up to date: |
| 151 | +```bash |
| 152 | +git submodule update --init |
| 153 | +``` |
| 154 | + |
| 155 | +Then, use the typical `cmake` workflow. Usage of `-DCMAKE_CXX_STANDARD=17` is optional, |
| 156 | +but recommended in order to have the largest set of features enabled: |
| 157 | +```bash |
| 158 | +mkdir build |
| 159 | +cd build |
| 160 | +cmake .. -DCMAKE_CXX_STANDARD=17 |
| 161 | +make |
| 162 | +``` |
| 163 | + |
| 164 | +To run the tests, simply call: |
| 165 | +```bash |
| 166 | +make test |
| 167 | +``` |
| 168 | +You can find the unit tests in `tests/basic.cpp`. |
| 169 | + |
| 170 | +## Acknowledgement |
| 171 | + |
| 172 | +This project is inspired by Rusts [`dbg!(…)` macro](https://doc.rust-lang.org/std/macro.dbg.html). |
0 commit comments