#Define Entire function call with arguments? - c

I have a program that I am running on two different compilers, and each compiler has a different file handling library. For example on library requires:
fwrite(buffer,size,elements,file)
While the other is:
f_write(file,buffer,size,elements)
is there anyway I could use a global #define in my main header file inside of a #ifdef statement that would allow me to seamlessly transition between compilers?

Sure:
#ifdef STUPID_COMPILER
# define fwrite(ptr, size, nitems, stream) f_write(stream, ptr, size, nitems)
#endif
Then just use fwrite() in your code -- no wrapper function needed. The preprocessor will translate it to an f_write() call if you're using the compiler/library that requires that.

You could make a new function:
size_t my_fwrite(...)
{
#ifdef REAL_FWRITE
return fwrite(buffer,size,elements,file);
#elif F_WRITE
return f_write(file,buffer,size,elements);
#else
#error "No fwrite"
#endif
}
What kind of implementation doesn't provide fwrite but has f_write ?

Related

Stripping specific functions on compile time

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
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.
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.

How to override assert macro in C?

I want to create my own version of assert in which it does some log prints in case assert was called in NDEBUG mode.
I tried to do the LD_PRELOAD trick and redefine the assert macro but it seems to ignore the macro definition completely and overriding __assert_fail is irrelevant since it isn't called in case of NDEBUG.
How can I override the libc assert macro?
I do not want to create a different function since assert is already used heavily in the project.
Had the same problem using gcc on Cygwin/Windows and on Linux.
My solution is to overwrite the (weak) definition of the actual assertion failed handling function. Here is the code:
/*!
* Overwrite the standard (weak) definition of the assert failed handling function.
*
* These functions are called by the assert() macro and are named differently and
* have different signatures on different systems.
* - On Cygwin/Windows its __assert_func()
* - On Linux its __assert_fail()
*
* - Output format is changed to reflect the gcc error message style
*
* #param filename - the filename where the error happened
* #param line - the line number where the error happened
* #param assert_func - the function name where the error happened
* #param expr - the expression that triggered the failed assert
*/
#if defined( __CYGWIN__ )
void __assert_func( const char *filename, int line, const char *assert_func, const char *expr )
#elif defined( __linux__ )
void __assert_fail ( const char* expr, const char *filename, unsigned int line, const char *assert_func )
#else
# error "Unknown OS! Don't know how to overwrite the assert failed handling function. Follow assert() and adjust!"
#endif
{
// gcc error message style output format:
fprintf( stdout, "%s:%d:4: error: assertion \"%s\" failed in function %s\n",
filename, line, expr, assert_func );
abort();
}
The C99 rationale provides a sample on how to redefine the assert in a good way on page 113:
#undef assert
#ifdef NDEBUG
#define assert(ignore) ((void)0)
#else
extern void __gripe(char *_Expr, char *_File, int _Line, const char *_Func);
#define assert(expr) \
((expr) ? (void)0 :\
__gripe(#expr, _ _FILE_ _,_ _LINE_ _,_ _func_ _))
#endif
I'd include assert.h right before this code to make sure assert.h is used.
Also notice that it calls a function that would do reporting logic, so that your code would be smaller.
It is a pretty simple thing to do, since assert is a macro. Given that you have this code:
#define NDEBUG
#include <assert.h>
int main( void )
{
assert(0);
return 0;
}
Then just do:
#ifdef NDEBUG
#undef assert
#define assert(x) if(!(x)){printf("hello world!");} // whatever code you want here
#endif
Note that this has to be done after #include <assert.h> though.
So if you want to stick your own definition into a common header file, and then use that header file to modify existing code, then your header file have to be included after assert.h.
my_assert.h
#include <assert.h>
#include <stdio.h>
#ifdef NDEBUG
#undef assert
#define assert(x) if(!(x)){printf("hello world!");}
#endif
main.c
#define NDEBUG
#include <assert.h>
#include "my_assert.h"
int main( void )
{
assert(0); // prints "hello world!"
assert(1); // does nothing
return 0;
}
An attempt to try to override the assert() macro in a large codebase can be difficult. For example, suppose you have code like:
#include <assert.h>
#include "my_assert.h"
#include "foo.h" // directly or indirectly includes <assert.h>
After this, any use of assert() will again use the system assert() macro and not the one that you have defined in "my_assert.h" (this is apparently part of the C design of the assert macro).
There are ways to avoid this, but you have to use nasty tricks like putting your own assert.h header in the include path before the system assert.h, which is somewhat error prone and non-portable.
I'd recommend using a different named macro than assert, and use regex tricks or a clang-rewriter to rename the various assert macros in your codebase to an assert macro that you can control. Example:
perl -p -i -e 's/\bassert\b *\( */my_assert( /;' `cat list_of_filenames`
(then adding "my_assert.h" or something like it to each of the files modified)
You can check if NDEBUG is defined and if it is then print whatever logs you want to print.

How to use external macro in function body?

I'm writing a function that should have two versions: a debug version and non-debug version. Which one of the two functions is used should be decided by the caller.
I want something like this:
caller.c
// comment out the following line when not necessary anymore
#define MY_FUNC_DEBUG
#include "my_func.h"
// some code that calls my_func()
my_func.h
void my_func(void);
my_func.c
void my_func()
{
// lots of code
#ifdef MY_FUNC_DEBUG
// debug code
#endif
// more code
}
This obviously won't work, because my_func.c is compiled separately from caller.c, therefore it can't know what macros it defined.
How can I make this work easily? I wouldn't want to write the two versions of my_func separately, because they share most of their code.
Assuming that you are using gcc, this problem can be easily solved by defining the macro at compile time via the -D option in both files.
In your example you could compile both files using -D MY_FUNC_DEBUG when you want the debug code to be activated and nothing otherwise. There is not need for defining MY_FUNC_DEBUG in caller.c.
Make the debugging code in my_func() switchable at run-time.
my_func.h
#ifndef MY_FUNC_H_INCLUDED
#define MY_FUNC_H_INCLUDED
extern int my_func_debug(int level);
extern void my_func(void);
#endif
my_func.c
#include "my_func.h"
static int debug = 0;
int my_func_debug(int level)
{
int rv = debug;
debug = level;
return rv;
}
void my_func(void)
{
...
#ifdef MY_FUNC_DEBUG
if (debug)
...debug...
#endif
...
}
caller.c
void consumer(void)
{
int old = my_func_debug(9);
my_func();
my_func_debug(old);
}
Discussion
The outline code means that you can have one copy of the source for my_func.c, but it can be compiled with debug included, or with it excluded. The consumer code (caller.c) can request the level of debugging it wants, but whether that does anything useful depends on whether the copy of my_func.o (my_func.obj on Windows) was compiled with debug included. You get one source file; you get to choose which variant of the object file is included in the program with caller.o. And at runtime you can request debugging.
Note that my_func_debug() is unconditionally defined; it just doesn't do anything very useful if the my_func.c code is not compiled with -DMY_FUNC_DEBUG.

What's the use of defining ARGS in a different header file?

So I've been going through some code, and there's some things I can't understand.
I have two header files. One is called 'args.h' and in that there are these statements, amongst others:
#if (defined(__cplusplus) || defined(__STDC__) || defined(c_plusplus))
#define NEW_STYLE 1
#define VOID void
#define ARGS(parenthesized_list) parenthesized_list
#else
#define NEW_STYLE 0
#define VOID
#define ARGS(parenthesized_list) ()
#define const
#endif
#if !defined(EXIT_SUCCESS)
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif
In the other header file, function prototypes are declared like this:
#if defined(__cplusplus)
extern "C" {
#endif
extern void yyerror ARGS((const char *s_));
extern int yylex ARGS((void));
extern int yyparse ARGS((void));
extern int yywrap ARGS((void));
#if defined(__cplusplus)
}
#endif
and a bunch of other stuff.
So my questions are:
1> What exactly does #define const do?
2> Why is arg declared in the other header file? Couldn't we simply declare the functions like a normal extern void a(const char *s__)? Or is this simply a preference of style?
Thanks.
This is to allow the code to compile with a pre-standard C compiler. It turns a function prototype into a function declaration, and simply removes const completely.
If you need to use a compiler so ancient that it doesn't understand prototypes or const, you have little choice but to use something like this. Otherwise, you're generally best off eliminating these horrible kludges.
20 years ago, code like this was common and necessary. It seems harder to excuse today, but I suppose there may still be a few platforms for which a reasonably modern compiler isn't available.
That are tweaks to make the code portable among compilers lacking this or that feature
is removing const everywhere (for sure not a good idea if you have a modern compiler)
this has to do with the ANSI C Syntax

Variable arguments in a Macro

I have a function which takes variable arguments, something like the following
int log_data (LOG_TYPE eType, ...)
{
/** some logging related stuff here **/
}
In the header file, I use something like
#ifdef LOGGING_ENABLED
int log_data (int nType, ...);
#else
#define log_data(_x_, ...)
#endif
Basically, the idea is to SWITCH debugging ON & OFF ~~~
Problem:
The above logic works perfectly fine in Linux & gcc, but errors outs during compilation in Windows VC++.
Variadic macros are relatively new, for example: this reference says that "Support for variadic macros was introduced in Visual C++ 2005." You might have an older version.
Edit: you are declaring log_data if you want debugging, and not if you don't. This means that you have the definition of the function in an #ifdef as well. As long as you're doing this, a solution would be:
int log_data (int nType, ...)
{
#ifdef LOGGING_ENABLED
/* the code to do logging */
#else
return 0; /* or whatever */
#endif
}
and in your header file, declare the function as usual:
int log_data (int nType, ...);
This has a disadvantage that the function call exists even when you're not logging, but the advantage is that it will work without preprocessor support for varargs.
Older versions of VC++ do not support variable arguments in macros.
You can use this trick to get around it:
#ifdef LOGGING_ENABLED
#define log_data log_data_impl
#else
#define log_data
#endif
// usage:
log_data(level, ...)
UPDATE - Another possible workaround:
#ifdef LOGGING_ENABLED
#define log_data(P) log_data_impl P // no braces around P!
#else
#define log_data(P)
#endif
// usage: we have to use two braces
log_data((level, ...));

Resources