Printf debugging done the right way
- Header-only.
- No additional dependencies.
- Output can be redirected.
- Crossplatform.
- Free for all (MIT license).
Code:
#include "trace-out.hpp"
int main(int argc, const char *argv[])
{
$f // pretty-print when function is called and returned
$t("ah sh1t, here we go again.");
int answer {42};
std::string moto {"hellomoto!"};
$t(answer, moto); // print "answer" and "moto" values
$if (answer == 42) // print condition value
$return answer; // print return value
$return 0; // print return value
}
Output:
int main(int argc, const char *argv[])
{
// ah sh1t, here we go again.
answer = 42
moto = "hellomoto!"
if (answer == 42) => true
{
return 42
}
} // int main(int argc, const char *argv[])
You can get it any way you want, as long as it's one of these
$ git clone --recurse-submodules https://github.com/shrpnsld/trace-out # Download
$ cd trace-out; mkdir build; cd build; cmake .. # Generate build files
$ cmake --install . # Install
$ git clone --recurse-submodules https://github.com/shrpnsld/trace-out # Download
$ cd trace-out; mkdir build; cd build; cmake .. # Generate build files
$ cmake --build . --target trace-out.hpp # Generate single header
Then, you can find single header at trace-out-amalgamated/include/trace-out/trace-out.hpp
inside the build directory.
trace-out has several macros defined that pretty-print information about code.
$t(<expression>)
[C++98] – print value of a given expression. Can be used inside other expressions.
$t(<expression>, ...)
[C++11 and later] – same as above, but it can accept multiple values. However, when it is passed multiple values, it can't be used inside other expressions.
$t("<C-string-literal>")
– print some string.
$tbin(<expression>)
, $toct(<expression>)
, $thex(<expression>)
– [C++98] – print binary, octal or hexadecimal representaions for a value of a given expression. Only numerical types are supported. When using floating point types with $tbin(...)
, it prints binary format representation, but $toct(...)
and $thex
print octal and hexadecimal values for each byte of the value. Can be used inside other expressions.
$tbin(<expression>, ...)
, $toct(<expression>, ...)
, $thex(<expression>, ...)
– [C++11 and later] – same as above, but it can accept multiple values. However, when it is passed multiple values, it can't be used inside other expressions.
$tr(<begin>, <end>|<how_much>)
– print values from a range defined by a pair of iterators or iterator and item count.
$m(<pointer>, <size>, [$<base>], [$grp(<count>)], [$be|$le], [$col(<count>)])
– print memory under <pointer>
.
<pointer>
– address of the memory to be printed<size>
– size of the memory in bytes$<base>
– numerical base; can be one of the following values:$bin
– binary$hex
– hexadecimal$sdec
– signed decimal$udec
– unsigned decimal$flt
– currentfloat
type$dbl
– currentdouble
type$ldbl
– currentlong double
type
$grp(<count>)
– how much bytes should be grouped together in a single column (1
,2
,4
or8
); this affects only$bin
,$hex
,$sdec
,$udec
bases$be
and$le
– big-endian and little-endian byte orders, respectively; if not specified, the current byte order is used$col(<count>)
– print memory in specified column count; if printing exceeds output stream width, then more optimal value will be calculated
$<base>
, $grp
, $be
, $le
and $col
are all optional and non-positional, but should always be listed after <pointer>
and <size>
.
The default memory representation is single-byte hexadecimals, with column count set to the maximum power of 2 that fits console width.
$if(<condition>)
– pretty-print if
statement.
$for(<statements>)
– pretty-printfor
loop.
$while(<condition>)
– pretty-print while
loop.
$f
– print function call start and call end labels. Must be used inside a function.
$return <expression>
– print expression value passed to the return
statement.
$s(...)
– trace statement execution.
Macros $f
, $if
, $for
and $while
shift output indentation inside their scope, while each thread keeps its own indentation.
$thread(<name>)
– set thread name that will be printed in the thread header.
$time(<name>, <any-code>)
– measure code execution time in milliseconds.
$clocks(<name>, <any-code>)
– measure code execution time in clocks.
$time_stats(<name>, <passes>, <any-code>)
– gather code execution time measurements in milliseconds and print statistics (average, median, mode, range) each time number of passes has reached <passes>
value.
$clock_stats(<name>, <passes>, <any-code>)
– gather code execution time measurements in clocks and print statistics (average, median, mode, range) each time number of passes has reached <passes>
value.
- all fundamental types, raw pointers, most of standard library types
- types that define member functions
.begin()
and.end()
which return iterators - sturctures and classes with data members or member functions
x
,y
,z
,w
,width
,height
,origin
,size
,left
,top
,right
,bottom
,real
,imag
in both lowcase and Capital
You can customize trace-out's behavior by defining the following macros.
TRACE_OUT_MARKER
<string>
– add text marker before every trace-out line.
TRACE_OUT_SHOW_FILE_LINE
– print file and line.
TRACE_OUT_STRIP_SCOPE
<how-much>
– show only <how-much>
scope components when using $f
macro.
TRACE_OUT_INDENTATION
<string>
– string that is used as an indentation. Default value is 4 spaces.
TRACE_OUT_SHOW_THREAD
– show thread information.
TRACE_OUT_OFF
– turn trace-out off.
TRACE_OUT_SYNC_STREAM
– enable output syncronization.
TRACE_OUT_STREAM_WIDTH
<how-much>
– width to which output is wrapped (actually, only memory output is wrapped).
TRACE_OUT_STREAM_TO_ENDPOINT
"<host>:<port>"
– stream to a specified <host>
and <port>
.
TRACE_OUT_STREAM_TO_FILE
"<file-path>"
– stream to a specified file.
TRACE_OUT_STREAM_TO_WDO
– stream to Windows debug output.
If predefined redirections aren't enough, you can make your own (though with some involvement). To do this:
- Create a derived implementation of
std::basic_streambuf<char>
that outputs wherever you want. - Create function
std::ostream &stream()
within some namespace. This function should returnstd::ostream
instance, which uses your implementation ofstd::basic_streambuf<char>
. - Define macro
TRACE_OUT_STREAM_TO
with the namespace where you've createdstd::ostream &stream()
.
As an example, look at trace-out-to-endpoint.hpp
or trace-out-to-wdo.hpp
in src/trace-out/
directory.
TRACE_OUT_CPP_VERSION
<number>
– specify C++ standard version using same format as __cplusplus
macro. Why? Visual Studio defines __cplusplus
macro with the wrong value, and while it offers a fix with /Zc:__cplusplus
, it can still cause issues in your project's code. So, to keep your project intact, you can use this macro, and it will only affect trace-out.