remove debug strings in release build - c

I use a LOG_DEBUG function to print debug information to the screen. I used a #define _DEBUG to disable LOG_DEBUG function by defining _DEBUG FLAG in compile time (release time). but linux strings commands of release build app still shows debug strings which exists in the compiled app. so what is the alternatives to eliminate arguments of LOG_DEBUG?
#ifdef _DEBUG
#define LOG_DEBUG(fmt, ...) printf("[D][%s:%d %s]", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
#define LOG_DEBUG(fmt, ...)
#endif
LOG_DEBUG("this is a debug string"); // "this is a debug string" exists in app release build yet
the compiler I use: ARM/Thumb C/C++ Compiler, RVCT3.1 [Build 569]
optimization: -O3

You could try using stringification:
#include <stdio.h>
#define _DEBUG
#ifdef _DEBUG
#define LOG_DEBUG(str) do { printf("[D][%s:%d %s] ", \
__FILE__, \
__LINE__, \
__FUNCTION__); \
puts(#str); } while(0)
#else
#define LOG_DEBUG(str)
#endif
int main() {
LOG_DEBUG(this is a debug string);
return 0;
}
Note: I tested this in clang, which doesn't exhibit the behaviour you described.

Related

Variadic arguments don't work in AIX 5.3 on CC compiler

I currently have a bunch of debug macros (hijacked from Zed's book Learn C The Hard Way) and I'm trying to compile them on AIX. The macros:
#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, s ...)
#else
#define debug(M, s ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ## s)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, s ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ## s)
#define log_warn(M, s ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ## s)
#define log_info(M, s ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ## s)
#define check(A, M, s ...) if(!(A)) { log_err(M, ## s); errno=0; goto error; }
#define sentinel(M, s ...) { log_err(M, ## s); errno=0; goto error; }
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, s ...) if(!(A)) { debug(M, ## s); errno=0; goto error; }
#endif
When I compile my project that imports these macros, the AIX CC compiler prints compiler errors with this message, and then exits normally:
"src/dbg.h", line 13.19: 1506-211 (S) Parameter list must be empty, or consist of one or more identifiers separated by commas.
It prints one of these to every line in the project that use one of the macro functions.
I've tried setting #pragma langlvl (stdc99) and #pragma langlvl (extc99) as advised in this article with no success.
I've also written a small example to see if I can compile it, as follows:
/* file "test.c" */
#include <stdio.h>
#define PRINTERROR(M, s...) fprintf(stderr, "ERROR MSG: " M "\n", ## s)
int main(void) {
PRINTERROR("no args");
PRINTERROR("with args: %s", "foo");
return 0;
}
The compiler emits the following message:
"test.c", line 4.24: 1506-211 (S) Parameter list must be empty, or consist of one or more identifiers separated by commas.
I'm using AIX 5.3 and CC for AIX version 6.0.0.0.
Your code -- either the original version or the edited one, which is using a non-standard extension, see the answer by ouah -- compiles fine for me on AIX 6.1 using XL C/C++ v11.1.
You state that your compiler is CC for AIX version 6.0.0.0. If that is to mean "IBM VisualAge C++ Professional for AIX, V6.0", that version was announced in 2002, i.e. is not really up to date...
Variadic macros in turn were included in the standard only in 1999, so it's quite possible your version of the compiler does not support them yet.
The form:
#define debug(M, s ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ## s)
with s ... is not C but a GNU extension to C. See gcc documentation that states:
If your macro is complicated, you may want a more descriptive name for the variable argument than VA_ARGS. CPP permits this, as an extension. You may write an argument name immediately before the ‘...’; that name is used for the variable argument. The eprintf macro above could be written
#define eprintf(args...) fprintf (stderr, args)
using this extension.
The correct C form for your debug macro would be:
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__,
__LINE__, __VA_ARGS__)

What is the standard way to log a program in C?

Programs in C that have --verbose or --debug option, how they actually implement it? Without using 3rd party libraries.
My goal is not to do this all the time:
if(debug) printf("Debug msg\n");
printf("Info msg\n");
The most common I've seen is to print to stderr.
#ifdef DEBUG
#define DEBUG_MESSAGE(fmt, ...) fprintf(stderr, fmt ## "\n", __VA_ARGS__)
#else
#define DEBUG_MESSAGE(fmt, ...)
#endif
Elsewhere...
DEBUG_MESSAGE("VERBOSE: %s", "This is a verbose message.");
EDIT
Something that would work at runtime:
#define DEBUG_MESSAGE(fmt, ...)\
do{\
if(g_debugEnabled) fprintf(stderr, fmt ## "\n", __VA_ARGS__);\
}while(0)
Which can be used similarly.
LAST EDIT
Changed to use arbitrary format string with __VA_ARGS__.
You can refer the below program where a macro is defined and based on the option passed to the executable logging is enabled.
#include <stdio.h>
#include <string.h>
#define STREQ(a, b) !(strcmp((a), (b)))
#define logmsg(fmt, ...) \
do { \
if (debug) \
printf(fmt, ##__VA_ARGS__);\
}while(0)
char debug;
int main(int argc, char *argv[])
{
if (argc > 1) {
if ( STREQ(argv[1], "debug"))
debug = 1;
}
logmsg("%s\n", "hello_world");
return 0;
}
Pass debug as the first argument to the executable to enable logging
Note : This program has been tested on Linux with gcc compiler

How to enable custom TRACE macro for specific files only?

I wrote the following trace macro in a file named "debug.h".
#define TRACE(x) \
printf( \
"%s(%d): ", \
__FILE__, \
__LINE__ \
); \
\
printf(x);
In debug I'd like to enable the macro only for certain files since resources are limited on the platform that I'm using. I don't want to completely remove the TRACE calls from the files. Just disable them.
Is there a clean way to do this in C using the preprocessor?
In debug.h:
#if TRACE_ENABLE
#define TRACE(x) \
printf( \
"%s(%d): ", \
__FILE__, \
__LINE__ \
); \
\
printf(x);
#else
#define TRACE(x)
#endif
Then, in your source files where you don't want trace:
#define TRACE_ENABLE 0
#include "debug.h"
or just:
#include "debug.h"
In source files to enable trace:
#define TRACE_ENABLE 1
#include "debug.h"
While both answers seems good to me, I think Giuseppe's answer is more useful most of the time since if you use this macro many times in a file, and you want to switch debug on/off for complete files, pmg's method is exhausting.
The important thing is to not forget adding the else statement: #else TRACE(X); if you want to edit it in the specific file and not in header, use:
#ifdef TRACE
#undef TRACE
#endif
#define TRACE(X)
A trick I've used somtimes is the use of a bit mask to enable a subset of the files whete the TRACE is used:
File1.c:
#if TRACE_MASK & 0x01
#define TRACE(x) ...
#endif
File2.c:
#if TRACE_MASK & 0x02
#define TRACE(x) ...
#endif
...
Then you can define your TRACE_MASK macro in the preprocessing options: /DTRACE_MASK=0x03 to enable the trace on both File1.c and File2.c
The only problem is that there is a limited numner of bits... (but you can use more than one macro: TRACE_MASK1, TRACE_MASK2...)
Bye
EDIT: of course you can write tdefinition once in a file "trace.h", and just redefine the mask in each source:
File trace.h:
#if TRACE_MASK & TRACE_CURRENT
#define TRACE(x) ...
#else
#define TRACE(x) do {} while(0)
#endif
File1.c:
#define TRACE_CURRENT 0x01
#include "trace.h"
File2.c:
#define TRACE_CURRENT 0x02
#include "trace.h"
What about
#define TRACE(x, y) do if (y) {/*your prints*/} while (0)
and also
#define TRACE_ENABLE 1
or
#define TRACE_ENABLE 0
at the top of your sources.
Then replace the TRACE invocations with
TRACE(foo, TRACE_ENABLE);

turning off DEBUG macros for a specific function (NDEBUG)

I am using the following macro for printing debug information that I found on the web. It works great.
However, I would like to turn-off debug printing for function A when debugging function B, which calls function A. I tried #define NDEBUG function A #undef NDEBUG but haven't managed to suppress printing in function A.
Any help will be greatly appreciated.
Any suggestions for alternative ways of accomplishing the task is also welcome.
Thanks ~RT
#ifdef NDEBUG
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
maybe you should wrap the trace into a module so that you can turn on/off the tracing dynamically in run-time and in that way you can specifically turn it off for a function call. In release mode you could replace all tracing with empty statements although in my experience I find it good to keep tracing in release mode as well - just in case.
NDEBUG is useful at the time assert.h is included, so #define NDEBUG/#undef NDEBUG later will not do anything.
You can do something like this though:
#if defined(NDEBUG) || !defined(MY_DEBUG)
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
Then, in function A():
...
#undef MY_DEBUG
result = B();
#define MY_DEBUG
...
This will debug B() when it's called from anywhere except from A(). To get debugging, you will need MY_DEBUG to be defined and NDEBUG to be undefined.
Edit: You will need to define MY_DEBUG when you want to compile with debugging, but hopefully you're using make or some other build tool, so this should be easy.

Debug Print Macro in C?

in C, what is the proper way to define a printf like macro that will print only when DEBUG symbol is defined?
#ifdef DEBUG
#define DEBUG_PRINT(???) ???
#else
#define DEBUG_PRINT(???) ???
#endif
where ??? is where I am not sure what to fill in
I've seen this idiom a fair amount:
#ifdef DEBUG
# define DEBUG_PRINT(x) printf x
#else
# define DEBUG_PRINT(x) do {} while (0)
#endif
Use it like:
DEBUG_PRINT(("var1: %d; var2: %d; str: %s\n", var1, var2, str));
The extra parentheses are necessary, because some older C compilers don't support var-args in macros.
#ifdef DEBUG
#define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while( false )
#else
#define DEBUG_PRINT(...) do{ } while ( false )
#endif
Something like:
#ifdef DEBUG
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, fmt, ## args)
#else
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#endif
Thank you mipadi, I improved your DEBUG_PRINT with file information too.
#define DEBUG 3
#if defined(DEBUG) && DEBUG > 0
#define DEBUG_PRINT(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \
__FILE__, __LINE__, __func__, ##args)
#else
#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */
#endif
Tested with latest clang, e.g.
int main(int argc, char **args) {
DEBUG_PRINT("Debugging is enabled.\n");
DEBUG_PRINT("Debug level: %d", (int) DEBUG);
}
outputs:
DEBUG: debug.c:13:main(): Debugging is enabled.
DEBUG: debug.c:14:main(): Debug level: 3
Use different signatures of DEBUG_PRINT, they don't have to be the same, like:
#ifdef DEBUG
#define DEBUG_PRINT printf
#else
#define DEBUG_PRINT(...)
#endif
this way on debug mode the DEBUG_PRINT call will be replaced with printf. On release it will ignore all arguments used previously.
Hope it helps.
You can simply use:
#ifdef DEBUG
#define DEBUG_PRINT printf
#else
#define DEBUG_PRINT
#endif
I like this way the best because it wont add any asm instructions to your release build.
#define DEBUG
#ifdef DEBUG
#define debug_printf(fmt, ...) printf(fmt, __VA_ARGS__);
#else
#define debug_printf(fmt, ...) /* Do nothing */
#endif
I see some minor errors in this implementation. So, here is my approach:
#ifdef DEBUG
#define DEBUG_PRINTF(...) printf("DEBUG: "__VA_ARGS__)
#else
#define DEBUG_PRINTF(...) do {} while (0)
#endif
Example usage:
DEBUG_PRINTF("hello\n");
Then, if I build and run with the -DDEBUG define on in my C build options, like this:
# Build
gcc -Wall -Wextra -Werror -std=c11 -DDEBUG -o build/my_program \
my_program_tests.c my_program.c
# Run
build/my_program
then I see this output:
DEBUG: hello
But if I build withOUT the -DDEBUG define in my compiler C options, then I see no debug prints whatsoever.

Resources