Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro that replaces all calls to printf with nothing

Tags:

c++

macros

I want to create a macro that replaces all calls to printf, more specifically mbedtls_printf (which behaves the exact sameway as printf) with nothing.

I know I can use #define mbedtls_printf to replace mbedtls_printf with nothing, but this will still leave the parameters/parenthesis intact.

Edit - I forgot to mention that mbedtls_printf is a macro that replaces itself with sgx_printf

like image 717
Roymunson Avatar asked Nov 23 '18 05:11

Roymunson


3 Answers

I would go with:

#define printf(...) (0)

The benefit here is that it will continue to compile in cases where someone actually bothers to check the return from printf (rare but not unheard of).

like image 126
SoronelHaetir Avatar answered Sep 22 '22 11:09

SoronelHaetir


The following works, at least with gcc 8. A brief search suggests that variadic macros were introduced with C99:

#define printf(...) do { } while (0)

int main()
{
    printf("Hello %s?\n", "world");
    return 0;
}

You want to use the ol' "do {} while (0)" trick, in order to avoid surprises like:

if (something)
    printf("Something else");

will_this_be_invoked_or_not();

You can't make printf() disappear completely. Because this would make the next line a logical part of the preceding if statement. Hillarity ensues. That's why you still have to leave something in place.

like image 27
Sam Varshavchik Avatar answered Sep 19 '22 11:09

Sam Varshavchik


If you completely no-op out the printf statements, there may be a bug lurking. Consider the following code:

printf("Result is %d\n", DoSomethingVeryImportant());

When you replace the printf call with a macro, you likely still want to make sure the inner function call to DoSomethingVeryImportant() is invoked. Otherwise, you've changed the logic of your program.

And I suppose you might want to have your mbedtls_printf actually call printf for debug builds, but be a no-op in a retail build.

If all of the above is of value, consider this as mbedtls_printf.h:

#ifndef MBEDTLS_PRINTF_H
#define MBEDTLS_PRINTF_H

#include <stdarg.h>
#include <stdio.h>

#ifdef DEBUG_BUILD
inline int printf_stub(const char* s, ...)
{
    va_list args;
    va_start(args, s);
    vprintf(s, args);
    va_end(args);
}

#define mbedtls_printf(...) printf_stub(__VA_ARGS__)

#else
inline int printf_stub(...){return 1;}
#define mbedtls_printf(...) printf_stub(__VA_ARGS__)
#endif

#endif

Then in code:

#include <iostream>
#include "mbedtls_printf.h"

int ImportantFunction()
{
   std::cout << "Really important code" << std::endl;
   return 42;
}

int main()
{
    mbedtls_printf("Result of a very important step: %d\n", ImportantFunction());
    mbedtls_printf("This just happened");
    mbedtls_printf("Result of a another important step: ", 43, 44, ImportantFunction());
    return 0;
}

The compiler will optimize out the empty function call and still invoke ImportantFunction() as it was doing originally.

like image 40
selbie Avatar answered Sep 20 '22 11:09

selbie