3

I'm writing a C program that uses a custom logging function to debug my program. Whenever I compile my program as a release version, I want all of my logging functions to be stripped from the code so it won't show up if someone tries to disassemble it.

Take the following example:

#include <stdio.h>

void custom_logging_function(char* message)
{
    // Do something here
}

int main()
{
    custom_logging_function("Hello world"); // This call should be removed.
    return 0;
}

How could I make it so that the custom_logging_function and it's arguments aren't compiled into my program without having to write include guards everywhere throughout my code? Thank you

Paradoxis
  • 4,471
  • 7
  • 32
  • 66
  • Why do you care if they are stripped by the compiler or the linker? – too honest for this site Sep 05 '16 at 11:45
  • @Olaf a combination of things, first is performance and binary size and the second is so people won't be able to decompile my program and see free internal notes about the program if they want to tear it apart. – Paradoxis Sep 05 '16 at 11:57
  • Don't do premature optimisations! If you have a timing problem, profile your code. You seem to not have understood my comment. Of course you can replace the function by a dummy. Just leave the rest to the toolchain. No idea how that would inhibit decompilation. It is just a function less. (it really is interesting how programmers care about such things, but ignore much more important issues). – too honest for this site Sep 05 '16 at 12:15
  • This is best handled with version control. Make a branch of your project, which contains the debug prints. That way you don't have to clutter down your production code with hundreds of ugly compiler switches and "dead code". You rarely need the debug prints any longer when the project is past test & release anyhow. – Lundin Sep 05 '16 at 12:46

2 Answers2

6

You can use pre-processor flags, for example:

#include <stdio.h>

#ifdef DEBUG
void custom_logging_function(char* message)
{
    // Do something here
}
#else
#define custom_logging_function(x) ((void) 0)
#endif

int main()
{
    custom_logging_function("Hello world"); // This call should be removed.
    return 0;
}

With this code you will have to tell the "debug" target to define DEBUG, if you want to define something specifically for the "release" target you can replace #ifdef DEBUG with #ifndef NDEBUG and add the NDEBUG flag to the "release" definitions.


Edit:

Changed #define custom_logging_function(x) 0 to #define custom_logging_function(x) ((void) 0) inspired by @JoachimPileborg his answer.

tversteeg
  • 4,717
  • 10
  • 42
  • 77
  • I think `#define custom_logging_function(x) 0` should be `#define custom_logging_function(x)`, in order to avoid the warning: `statement with no effect` – David Ranieri Sep 05 '16 at 11:32
  • What about the arguments though, if someone decompiles it they could see a string `Hello world`, or does this prevent that too? – Paradoxis Sep 05 '16 at 11:33
  • @AlterMann if you define it to return 0 you can still use the function as a argument to another function. – tversteeg Sep 05 '16 at 11:35
  • 1
    @Paradoxis the `x` symbol is the argument, and it is ignored. So nothing will happen with the string, it won't even show up in the binary data. – tversteeg Sep 05 '16 at 11:36
  • Then, as pointed out by Joachim, `#define custom_logging_function(x) ((void) 0)` is a better option – David Ranieri Sep 05 '16 at 11:37
  • 1
    I agree, I have changed my answer to `((void)0)` instead of `0`. – tversteeg Sep 05 '16 at 11:38
  • There should be no macro, but just define an empty function. Never use macros if a function will do. – too honest for this site Sep 05 '16 at 11:39
  • Wouldn't a empty function save the string in the binary data if it's not optimized? If this is the case it would seem less desirable to me than using a macro. – tversteeg Sep 05 '16 at 11:48
  • See also http://stackoverflow.com/questions/679979/how-to-make-a-variadic-macro-variable-number-of-arguments to make variadic macros that can have any number of arguments. – Paul Ogilvie Sep 05 '16 at 12:21
3

Assuming you only want the logging calls to happen in a debug-build of your application, and not the release build you send to customers, you can still use the preprocessor and conditional compilation for it. It can be made vert simple though by using macros instead of having checks at every call.

Something like this in a heder file:

#ifdef _DEBUG
void custom_logging_function(char* message);
#else
# define custom_logging_function(message) ((void) 0)
#endif

You could use an empty macro body for the release-macro, but that can cause some compilers to give "empty statement" warnings. Instead I use an expression casted to void (to tell the compiler that the result of the expression will not be used). Any smart compiler will not include the expression after optimization.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621