🍦 Never use cout/printf to debug again



CI.badge LICENSE.badge

IceCream-Cpp is a little (single header) library to help with the print debugging on C++11 and forward.

Try it at godbolt!


With IceCream-Cpp, an execution inspection:

auto my_function(int i, double d) -> void
    std::cout << "1" << std::endl;
    if (condition)
        std::cout << "2" << std::endl;
        std::cout << "3" << std::endl;

can be coded instead:

auto my_function(int i, double d) -> void
    if (condition)

and will print something like:

ic| test.cpp:34 in "void my_function(int, double)"
ic| test.cpp:36 in "void my_function(int, double)"

Also, any variable inspection like:

std::cout << "a: " << a
          << ", b: " << b
          << ", sum(a, b): " << sum(a, b)
          << std::endl;

can be simplified to:

IC(a, b, (sum(a, b)));

and will print:

ic| a: 7, b: 2, (sum(a, b)): 9

This library is inspired by and aims to behave the most identical as possible to the original Python IceCream library.


The IceCream-Cpp is a one file, header only library, having the STL as its only dependency. The most direct way to install it is just copy the icecream.hpp header to inside your project.

To properly install it system wide, together with the CMake project files, run on IceCream-Cpp project root directory:

mkdir build
cd build
cmake ..
cmake --install .


If using Nix, any committed version on master branch can be installed using the archive https://github.com/renatoGarcia/icecream-cpp/archive/<commmit>.tar.gz, where <commit>.tar.gz could be any tag or commit hash of master branch.

For instance, to install the master HEAD commit, environment wide:

nix-env -if https://github.com/renatoGarcia/icecream-cpp/archive/master.tar.gz

To use a specific commit in a shell.nix:

icecream-cpp = pkgs.callPackage (
  fetchTarball https://github.com/renatoGarcia/icecream-cpp/archive/<commit>.tar.gz
) { inherit pkgs; };

where pkgs is the variable with the evaluated nixpkgs.


The released versions are available on Conan too:

conan install icecream-cpp/[email protected]


If using CMake:


will add the installed directory on include paths list.

After including the icecream.hpp header on a source file, here named test.cpp:

#include <icecream.hpp>

A macro IC(...) will be defined. If called with no arguments it will print the prefix (default ic| ), the source file name, the current line number, and the current function signature. The code:

auto my_function(int foo, double bar) -> void
    // ...
    // ...

will print:

ic| test.cpp:34 in "void my_function(int, double)"

If called with arguments it will print the prefix, those arguments names, and its values. The code:

auto v0 = std::vector<int> {1, 2, 3};
auto s0 = std::string {"bla"};
IC(v0, s0, 3.14);

will print:

ic| v0: [1, 2, 3], s0: "bla", 3.14: 3.14

Return value

If called with no arguments the IC(...) macro will return void, if called with one argument it will return the argument itself, and if called with multiple arguments it will return a tuple with all of them:

auto a = int {7};
auto b = std::string {"bla"};
auto c = float {3.14};

int& d = IC(a);
std::tuple<std::string&, float&> e = IC(b, c);


The Icecream class is internally implemented as a singleton. All the configuration changes will be done to a unique object, and shared across all the program and threads.

All configurations are done/viewed through accessor methods, using the icecream::ic object. To allow the method chaining idiom all the set methods return a reference of the ic object:

    .prefix("ic: ")

For simplification purposes, on the following examples a using icecream::ic statement will be presumed.


Enable or disable the output of IC(...) macro, enabled default.

  • set:
    auto enable() -> IcecreamAPI&;
    auto disable() -> IcecreamAPI&;

The code:


will print:

ic| 1: 1
ic| 3: 3


Warning: this method will return a reference to the internal std::ostream. The operations done on that reference will not be thread safe.

The std::ostream where the output will be streamed.

  • get:
    auto stream() -> std::ostream&;

The default stream buffer associated is the same as std::cerr, but that can be changed. For instance, to stream the output to a string:

auto sstr = std::stringstream {};


The text that will be printed before each output. It can be set to a string, a nullary callable that returns an object having an overload of operator<<(ostream&, T), or any number of instances of those two. The printed prefix will be a concatenation of all those elements.

  • set:
    template <typename... Ts>
    auto prefix(Ts&& ...values) -> IcecreamAPI&;

The code:

ic.prefix("icecream| ");
ic.prefix([]{return 42;}, "- ");
ic.prefix("thread ", std::this_thread::get_id, " | ");

will print:

icecream| 1: 1
42- 2: 2
thread 1 | 3: 3


Controls if a char* variable should be interpreted as a null-terminated C string (true) or a pointer to a char (false). The default value is true.

  • get:
    auto show_c_string() const -> bool;
  • set:
    auto show_c_string(bool value) -> IcecreamAPI&;

The code:

char const* flavor = "mango";



will print:

ic| flavor: "mango";
ic| flavor: 0x55587b6f5410


The maximum number of characters before the output be broken on multiple lines. Default value of 70.

  • get:
    auto line_wrap_width() const -> std::size_t;
  • set:
    auto line_wrap_width(std::size_t value) -> IcecreamAPI&;


If the context (source name, line number, and function name) should be printed even when printing variables. Default value is false.

  • get:
    auto include_context() const -> bool;
  • set:
    auto include_context(bool value) -> IcecreamAPI&;


The string separating the context text from the variables values. Default value is "- ".

  • get:
    auto context_delimiter() const -> std::string;
  • set:
    auto context_delimiter(std::string const& value) -> IcecreamAPI&;

Printing logic

When printing a type T, the precedence is use an overloaded function operator<<(ostream&, T) always when it is available. The exceptions to that rule are strings (C strings, std::string, and std::string_view), char and bounded arrays. Strings will be enclosed by ", char will be enclosed by ', and arrays are considered iterables rather than let decay to raw pointers.

In general, if an overload of operator<<(ostream&, T) is not available to a type T, a call to IC(t) will result on a compiling error. All exceptions to that rule, when IceCream-Cpp will print a type T even without a operator<< overload are discussed below. Note however that even to those, if a user implements a custom operator<<(ostream&, T) that will take precedence and used instead.

C strings

C strings are ambiguous. Should a char* foo variable be interpreted as a pointer to a single char or as a null-terminated string? Likewise, is the char bar[] variable an array of single characters or a null-terminated string? Is char baz[3] an array with three single characters or is it a string of size two plus a '\0'?

Each one of those interpretations of foo, bar, and baz would be printed in a distinct way. To the code:

char flavor[] = "pistachio";

all three outputs below are correct, each one having a distinct interpretation of what should be the flavor variable.

ic| flavor: 0x55587b6f5410
ic| flavor: ['p', 'i', 's', 't', 'a', 'c', 'h', 'i', 'o', '\0']
ic| flavor: "pistachio"

The IceCream-Cpp policy is handle any bounded char array (i.e.: array with a known size) as an array of single characters. So the code:

char flavor[] = "chocolate";

will print:

ic| flavor: ['c', 'h', 'o', 'c', 'o', 'l', 'a', 't', 'e', '\0']

unbounded char[] arrays (i.e.: array with an unknown size) will decay to char* pointers, and will be printed either as a string or a pointer as configured by the show_c_string option.

Pointer like types

The std::unique_ptr<T> (before C++20) and boost::scoped_ptr<T> types will be printed like usual raw pointers.

The std::weak_ptr<T> and boost::weak_ptr<T> types will print their address if they are valid or "expired" otherwise. The code:

auto v0 = std::make_shared<int>(7);
auto v1 = std::weak_ptr<int> {v0};


will print:

ic| v1: 0x55bcbd840ec0
ic| v1: expired

Iterable types

If for a type A with an instance a, all following operations are valid:

auto it = begin(a);
it != end(a);

the type A is defined iterable, and if A has no overload of operator<<(ostream&, A), all of its items will be printed instead. The code:

auto v0 = std::list<int> {10, 20, 30};

will print:

ic| v0: [10, 20, 30]

Tuple like types

A std::pair<T1, T2> or std::tuple<Ts...> typed variables will print all of its elements.

The code:

auto v0 = std::make_pair(10, 3.14);
auto v1 = std::make_tuple(7, 6.28, "bla");
IC(v0, v1);

will print:

ic| v0: (10, 3.14), v1: (7, 6.28, "bla")

Optional types

A std::optional<T> typed variable will print its value, if it has one, or nullopt otherwise.

The code:

auto v0 = std::optional<int> {10};
auto v1 = std::optional<int> {};
IC(v0, v1);

will print:

ic| v0: 10, v1: nullopt

Variant types

A std::variant<Ts...> or boost::variant2::variant<Ts...> typed variable will print its value.

The code:

auto v0 = std::variant<int, double, char> {4.2};

will print:

ic| v0: 4.2

Exception types

Types inheriting from std::exception will print the return of std::exception::what() method. If beyond that it inherits from boost::exception too, the response of boost::diagnostic_information() will be also printed.

The code:

auto v0 = std::runtime_error("error description");

will print:

ic| v0: error description

Standard layout types (Clang only)

With some exceptions (see issue #7), if using Clang >= 7, any standard layout type (C compatible structs roughly speaking) is printable even without an operator<<(ostream&, T) overload.

The code:

class S
    float f;
    int ii[3];

S s = {3.14, {1,2,3}};

will print:

ic| s: {f: 3.14, ii: [1, 2, 3]}


The IC(...) is a preprocessor macro, then care must be taken when using arguments with commas. Any argument having commas must be enclosed by parenthesis. The code:

auto sum(int i0, int i1) -> int
    return i0 + i1;

// ...

IC((sum(40, 2)));

will work and print something like:

ic| (sum(40, 2)): 42

Also, since IC(...) is a preprocessor macro, it can cause conflicts if there is some other IC identifier on code. To change the IC(...) macro to a longer ICECREAM(...) one, just define ICECREAM_LONG_NAME before the inclusion of icecream.hpp header:

#include "icecream.hpp"

While most compilers will work just fine, until the C++20 the standard requires at least one argument when calling a variadic macro. To handle this the nullary macros IC0() and ICECREAM0() are defined alongside IC(...) and ICECREAM(...).

Similar projects

The CleanType library has a focus on printing readable types names, but there is support to print variables names and values alongside its types.

  • Simplest way to print function called with the arguments that were passed

    Simplest way to print function called with the arguments that were passed

    What is the simplest way to print function called with the arguments that were passed? I'm debugging an interface implementation, so I don't have so much control over who is calling me methods; rather I am on the receiving end of them being called.

    I can add IC() at the beginning of a function to see its name and arguments, but the argument values themselves aren't printed.

    opened by vadi2 6
  • avoid using the _() macro/function which used for text translation in other libraries

    avoid using the _() macro/function which used for text translation in other libraries

    Hi, I try to use the header file, but it reported a build error.

    I see that in some of my header file, the _() is defined to text translation. (For example, under wxWidgets, the _() is defined as:

     #define _(s)                               wxGetTranslation((s))

    While, I see in the icecream.hpp, it also define some function like:

        template<typename... Ts>
        auto _(std::string const& fmt, Ts&&... vs) -> detail::FormatterPack<decltype(std::forward<Ts>(vs))...>
            return detail::FormatterPack<decltype(std::forward<Ts>(vs))...>{fmt, std::forward<Ts>(vs)...};

    So, I would like to find a way to solve such conflict issue. Thanks.

    opened by asmwarrior 2
  • containers are not properly displayed when they are members of a user-defined class

    containers are not properly displayed when they are members of a user-defined class

    I'm trying to print an instance of a user-defined class as follows.

      class MyStruct {
        int i;
        double d;
        std::string s;
        std::vector<int> v;
      MyStruct x;
      x.i = 2; x.d = 0.9; x.s = std::string("abc"); x.v = {1, 2, 3};     // set member variables

    What I expected was something like

    ic| x: {i: 2, d: 0.9, s: "abc", v: [1, 2, 3]}

    but what I actually got was the following.

    ic| x: {i: 2, d: 0.9, s: {__r_: {}}, v: {}}

    It seems that a member variable is not properly displayed when it is an STL container. If I print each member IC(x.s, x.v), I got the correct output. Could someone investigate this issue?

    FYI, my compiler is Apple clang version 11.0.0 (clang-1100.0.33.17).

    opened by yohm 2
  • Printing a std::string_view relies on a terminating null-byte

    Printing a std::string_view relies on a terminating null-byte

    std::string str = "ABCDE";
    std::string_view sub{str.data() + 1, 3};
        // expected: ic| sub: "BCD"
        // actual:   ic| sub: "BCDE"

    (see https://godbolt.org/z/b3a9Eq)

    I think line 703

    buf << '"' << cv.to_bytes(value.data()) << '"';

    should be

    buf << '"' << cv.to_bytes(value.data(), value.data() + value.size()) << '"';

    and maybe the Microsoft-specific code a few lines above has to be adjusted, too.
    But I don't know icecream-cpp well enough to be sure.

    opened by siebenschlaefer 1
  • Linking errors

    Linking errors

    I was using version 0.1.0 of icecream-cpp for a while, and I have IC statements in multiple source files, which are compiled independently (as cmake object libraries) and then linked together into different binaries and shared libraries. This used to work very nicely. Now I upgraded to 0.3.0, recompiled everything, and get linking errors like so:

    multiple definition of `icecream::detail::show_c_string()'

    I know that this is potentially an issue with header only libraries in general, but perhaps there is something you can do, as it used to work in previous versions.

    opened by mrjackbo 1
  • Fix wide characters support.

    Fix wide characters support.

    Add tests to wide characters. Fix bug on MacOS when converting between same character types. Fix bug when printing string_view's without a terminating null-byte.

    fix #13

    opened by renatoGarcia 0
  • cannot display char as integer

    cannot display char as integer

    CleanShot 2022-09-03 at 10 51 31@2x

    #include <algorithm>
    #include <numeric> 
    #include "icecream.hpp"
    using namespace std;
    #define DETECT_TYPE(x)                        \
        do                                        \
        {                                         \
            IC(sizeof(x));                        \
            IC_("d", std::numeric_limits<x>::max());    \
            IC_("d", std::numeric_limits<x>::min());    \
            IC_("d", std::numeric_limits<x>::lowest()); \
        } while (0)
    int main(int argc, char **argv)
        DETECT_TYPE(unsigned char);
        return 0;

    expect: it should display max: 128, min: -127, lowest: -127 gcc 11.2 linux

    opened by logerrors 0
  • Release a new version

    Release a new version

    Just creating a git tag, and changing the version number in CMakeLists.txt would be good.

    The last release was 2 years ago, while there has been a bunch of new stuff added!

    opened by dufferzafar 0
  • Comparison with dbg-macro

    Comparison with dbg-macro

    I'm used to the Python icecream library and really like this style of printf based debugging.

    While looking for C++ based library, I found this repo & another one: https://github.com/sharkdp/dbg-macro

    Are you aware of it? Any comparison between the two? which features one supports & the other doesn't etc?

    opened by dufferzafar 5
  • Functionalities in <codecvt> are deprecated since C++ 17/20

    Functionalities in are deprecated since C++ 17/20

    Some functionalities in <codecvt> (e.g. std::codecvt<char16_t, char, std::mbstate_t>) are being deprecated since C++ 17/20. Please refer to https://en.cppreference.com/w/cpp/locale/codecvt for more details. Compiling with these usages may throw annoying warnings.

    opened by LyricZhao 1
  • Clang dump struct type info limitation

    Clang dump struct type info limitation

    Due to limited information provided by Clang when using __builtin_dump_struct function, some struct members types can not be printed. Enums, none of them can be printed. With arrays, only the ones with elements of fundamental types, fixed width integers, std::size_t, std::ptrdiff_t, and any pointer, declared using canonical names (i.e.: not type aliases), can be printed.

    When using the __builtin_dump_struct function, both enums and arrays are dumped to some_printf_func using the %p specifier, regardless of its elements type. With only that information would not be possible recover and print neither the enum values nor any array element.

    However, preceding each call to some_printf_func with a %p specifier by __builtin_dump_struct, a call to that same function will be done having as argument a string with the member signature (type and name). To enums that is not of any help, but to arrays, inspecting that string is possible deduce the array size and its elements types.

    Knowing that information, an array dumped with a preceding "short [50] bla" string can be deduced as being an array of 50 short int. That works identically for any fundamental type, but is not possible infer the array elements type if an alias is used. With the code:

    using Integer = int;
    struct Point
        double x;
        double y;
    struct S
        Integer integers[10];
        Point coords[5];

    there is no way to know what fundamental type Integer is an alias to, neither what are the internal members of Point struct. Consequently, both integers and coords members can not be printed.

    To enums, its values are represented using an integral type defined at enum declaration, like:

    enum EN : std::uint64_t

    However, inside of some_printf_func it's not possible to get that information. Therefore, not kowning the bit size of each enum value it's not possible print them.

    opened by renatoGarcia 0
Renato Garcia
Renato Garcia
A way to visualize your multithreaded Mbed OS application like never before!

MbedSysview Library A way to visualize your multithreaded Mbed OS application like never before! MbedSysview is a library that connects the Mbed OS ta

Jamie Smith 4 Aug 10, 2022
Creates an XDG_RUNTIME_DIR on login and never removes it.

dumb_runtime_dir Creates an XDG_RUNTIME_DIR directory on login per the freedesktop.org base directory spec. Flaunts the spec and never removes it, eve

Isaac Freund 16 Aug 13, 2022
让Etwhook再次伟大! Make InfinityHook Great Again!

MakeInfinityHookGreatAgain Make InfinityHook Great Again 图片测试(2004系统两个小时): 怎么做 https://key08.com/index.php/2021/06/23/1170.html windows 20h1 x64 18个小时

Huoji's 95 Sep 23, 2022
Pretend it's 1955 all over again.

Emmett Just run your program, jump in your DMC-12 and pretend it's 1955 all over again. How does that work? This works by relying on seccomp-ebpf, whi

Arthur Gautier 4 Sep 15, 2021
A simple DIY project that will make oldschool POCSAG pagers/beepers work again

Arduino POCSAG Transcoder Features Message types: Tone, Numeric, Alphanumeric 4 encodings: Latin, 2xLatin/Cyrillic, Cyrillic Data rates: 512, 1200, 24

SinuX 7 Aug 10, 2022
Make Epsilon Great again - Project Mu UEFI Firmware for Surface Duo (First Generation) Devices

Project Mu UEFI Implementation for Surface Duo Build Quick notes for building: Use Ubuntu 20.04 x64 Generate ACPI tables with IASL Follow this quick d

WOA Project 78 Oct 2, 2022
SuperTux Milestone 1 ported to the Dreamcast (again)

- An introduction for SuperTux - http://super-tux.sf.net/ Last update: April 26, 2004 Dreamcast port by Headshotnoby Turns out this game was alread

Headshotnoby 3 Jun 7, 2022
A fork of Picoprobe, an SWD progammer firmware, for the Pico Debug'n'Dump

pdnd-picoprobe A fork of Picoprobe, an SWD progammer firmware, for the Pico Debug'n'Dump. Usage Make sure the "Mode" switch is set to I2C/SWD Follow g

stacksmashing 16 Dec 15, 2021
debug esp32-c3 Ai-thinker board in platformio

Platformio Ai-thinker esp32-c3 project template with ability to debug using builtin USB JTAG. To be able to view periph regs while debugging, you need

null 4 Mar 4, 2022
Visual Studio native debugger extension to help debug native applications using Mono.

Unity Mixed Callstack UnityMixedCallstack is a Visual Studio 2017/2019 extension to help debug native applications embedding Mono, like Unity. If you

Unity Technologies 79 Sep 30, 2022
mimic of libc’s printf function (42 Project, mandatory part only)

42printf mimic of libc’s printf function (42 Project, mandatory part only) This hasn't been tested yet by moulinette and is not recommended to take as

null 1 Oct 26, 2021
Type-safe Printf in C

Type-Safe Printf For C This uses macro magic, compound literals, and _Generic to take printf() to the next level: type-safe printing, printing into co

Henrik Theiling 60 Jul 17, 2022
printf() implementation in C

ft_printf This project was made in accordance with the project of School 21 (Ecole 42). Preamble · Description · Examples · Installation and usage · T

null 5 Aug 19, 2022
Simple printf functionality for GLSL.

Simple printf functionality for GLSL. This library is a simple proof of concept of using printf directly from a shader. The main point of being able

null 204 Sep 24, 2022
Tools for interacting with music data in GBA games that use the Engine Software replayer.

A suite of tools for interacting with the XM-like music data found in certain Game Boy Advance games - specifically those that use the Engine Software replayer middleware.

Luna 17 Nov 16, 2021
A simple implementation of a parser and its use to calculate simple mathematical expressions

Calculator C Parser A simple implementation of a parser and its use to calculate simple mathematical expressions I haven't written a detailed descript

Romes 14 Nov 8, 2021
Trial port of the rtf_433 Library for use with OpenMQTTGateway on a ESP32 and a CC1101 Transceiver

This is an attempt at creating an Arduino library for use on ESP32 boards with a CC1101 transceiver with the device decoders from the rtl_433 package.

Northern Man 77 Sep 8, 2022
Some hypervisor research notes. There is also a useful exploit template that you can use to verify / falsify any assumptions you may make while auditing code, and for exploit development.

Introduction Over the past few weeks, I've been doing some hypervisor research here and there, with most of my focus being on PCI device emulation cod

Faith 127 Sep 14, 2022
OffensivePH - use old Process Hacker driver to bypass several user-mode access controls

offensiveph OffensivePH is a post-exploitation tool that utilizes an old Process Hacker driver to bypass several user-mode access controls. Usage Comp

Red Section 267 Sep 23, 2022