Use #Ifdefs and #Define to Optionally Turn a Function Call into a Comment

Use #ifdefs and #define to optionally turn a function call into a comment

Try this:

#ifdef SOMETHING
#define foo(x)
#else
#define foo(x) MyFunction(x)
#endif

If your function has several arguments, then:

#ifdef SOMETHING
#define foo(x,y,z)
#else
#define foo(x,y,z) MyFunction(x,y,z)
#endif

If your function has a variable number of arguments, then your compiler may support so-called "variadic macros", like this:

#ifdef SOMETHING
#define foo(...)
#else
#define foo(...) MyFunction(__VA_ARGS__)
#endif

The reason which I've seen this kind of thing used in practice is to get rid of logging functions from a release build. However, see also Separate 'debug' and 'release' builds? in which people question whether you should even have different builds.


Alternatively, instead of redefining the function call as nothing, Jonathan's comment to this answer suggested doing something like the following:

#ifdef SOMETHING
#define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
#else
#define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
#endif

The reasoning for doing this is so that the function call is always compiled (so it won't be left with gratuitous errors like references to deleted variables), but only called when needed: see Kernighan & Pike The Practice of Programming and also the Goddard Space Flight Center programming standards.

From a debug.h file (originating from 1990, and therefore not using __VA_ARGS__):

/*
** Usage: TRACE((level, fmt, ...))
** "level" is the debugging level which must be operational for the output
** to appear. "fmt" is a printf format string. "..." is whatever extra
** arguments fmt requires (possibly nothing).
** The non-debug macro means that the code is validated but never called.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#ifdef DEBUG
#define TRACE(x) db_print x
#else
#define TRACE(x) do { if (0) db_print x; } while (0)
#endif /* DEBUG */

With C99, there's no longer a need for the double parentheses trick. New code should not use it unless C89 compatibility is an issue.

How do you implement #ifdef in python?

If you just want to disable logging methods, use the logging module. If the log level is set to exclude, say, debug statements, then logging.debug will be very close to a no-op (it just checks the log level and returns without interpolating the log string).

If you want to actually remove chunks of code at bytecode compile time conditional on a particular variable, your only option is the rather enigmatic __debug__ global variable. This variable is set to True unless the -O flag is passed to Python (or PYTHONOPTIMIZE is set to something nonempty in the environment).

If __debug__ is used in an if statement, the if statement is actually compiled into only the True branch. This particular optimization is as close to a preprocessor macro as Python ever gets.

Note that, unlike macros, your code must still be syntactically correct in both branches of the if.


To show how __debug__ works, consider these two functions:

def f():
if __debug__: return 3
else: return 4

def g():
if True: return 3
else: return 4

Now check them out with dis:

>>> dis.dis(f)
2 0 LOAD_CONST 1 (3)
3 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (True)
3 JUMP_IF_FALSE 5 (to 11)
6 POP_TOP
7 LOAD_CONST 1 (3)
10 RETURN_VALUE
>> 11 POP_TOP

3 12 LOAD_CONST 2 (4)
15 RETURN_VALUE
16 LOAD_CONST 0 (None)
19 RETURN_VALUE

As you can see, only f is "optimized".

using #ifdef for different number of function argument depending on platforms

Given that you are changing all the calls to foo,

just change foo to the function with more parameters, then #ifdef internal to the function for different functionality.

void foo (int newarg, const char * a, int b, int c){
#ifdef __NEWPALTFORM__
#else
#endif
}

Also worth considering whether the parameters to the function should really be a struct, in which case new parameters in the future won't be much of an issue. Not enough context in your question to say whether this is a good idea or not

but it would be something like :=

typedef struct {
int newarg;
const char* a;
int b;
int c;
} fooType;

void foo(fooType f) // either by value or by pointer depending on context
{
// #ifdefs...
}

How do you perform macro expansion within #ifdef?

Is there more to your program than this question describes? The directive

#define MY_VAR(x) prefix_##x

defines exactly one preprocessor identifier. The call

blah ^&* blah MY_VAR(hello) bleh <>? bleh

simply goes in one end of the preprocessor and comes out the other without defining anything.

Without some other magic happening, you can't expect the preprocessor to remember what arguments have been passed into what macros over the course of the preceding source code.

You can do something like

#define prefix_test 1
#if MY_VAR(test) == 1
#undef prefix_test // optional, "be clean"
...
#endif
#undef prefix_test

to query whether the prefix currently has the particular value prefix_. (Undefined identifiers are replaced with zero.)

Why should #ifdef be avoided in .c files?

Hard to maintain. Better use interfaces to abstract platform specific code than abusing conditional compilation by scattering #ifdefs all over your implementation.

E.g.

void foo() {
#ifdef WIN32
// do Windows stuff
#else
// do Posix stuff
#endif
// do general stuff
}

Is not nice. Instead have files foo_w32.c and foo_psx.c with

foo_w32.c:

void foo() {
// windows implementation
}

foo_psx.c:

void foo() {
// posix implementation
}

foo.h:

void foo();  // common interface

Then have 2 makefiles1: Makefile.win, Makefile.psx, with each compiling the appropriate .c file and linking against the right object.

Minor amendment:

If foo()'s implementation depends on some code that appears in all platforms, E.g. common_stuff()2, simply call that in your foo() implementations.

E.g.

common.h:

void common_stuff();  // May be implemented in common.c, or maybe has multiple
// implementations in common_{A, B, ...} for platforms
// { A, B, ... }. Irrelevant.

foo_{w32, psx}.c:

void foo()  {  // Win32/Posix implementation
// Stuff
...
if (bar) {
common_stuff();
}
}

While you may be repeating a function call to common_stuff(), you can't parameterize your definition of foo() per platform unless it follows a very specific pattern. Generally, platform differences require completely different implementations and don't follow such patterns.


  1. Makefiles are used here illustratively. Your build system may not use make at all, such as if you use Visual Studio, CMake, Scons, etc.
  2. Even if common_stuff() actually has multiple implementations, varying per platform.

Conditional macro #define for a function - causing: function redefined warning

I found the answer to my question here.

Conclusion:
you cannot include #ifdef etc... inside #define, because there should only be one pre-processing directive per line.

So although we can break the line with a backslash '\' this helps writing readable multiline macros,
but the preprocessor will see it as one line:

#define doSomething(){ #if TARGET_IPHONE_SIMULATOR ... #endif }

Which throws this error:

error: '#' is not followed by a macro parameter.

That makes sense, so I will have to rethink my implementation.

#ifndef in javascript

As I presume you know, Javascript doesn't have preprocessor directives like C/C++, but you can use regular if statements that are evaluated at run-time like this:

if (typeof myFunc === "undefined") {
var myFunc = function(a,b) {
// body of your function here
}
}

or for a whole library of functions:

if (!window.controlUtilsDefined) {
window.controlUtilsDefined = true;

// put control library functions here

function aaa() {
// body here
}

function bbb() {
// body here
}

}

or if you want to check based on some other variable:

var myFunc;
if (debugMode) {
myFunc = function(a,b) {
// body of your function here
}
} else {
myFunc = function(a,b) {
// body of your alternate function here
}
}

If your concern is just that you have multiple copies of the exact same function names in the library that each control uses, that isn't technically a problem in Javascript. The last defined one will be the operative one, but if they're all the same that isn't technically a problem. Only one definition will exist in memory as the later definitions will replace the earlier ones.

If you control the source of the controls, then it would be better to break the common utilities out separately into their own JS file and have the host page just include that utilities script file once.

Or (with a little more work but no additional responsibilities for the host page), each control could dynamically load their utlities from an external JS file and check a known global variable to see if some other control has already loaded the common external JS.

Indenting #defines

Pre-ANSI C preprocessor did not allow for space between the start of a line and the "#" character; the leading "#" had to always be placed in the first column.

Pre-ANSI C compilers are non-existent these days. Use which ever style (space before "#" or space between "#" and the identifier) you prefer.

http://www.delorie.com/gnu/docs/gcc/cpp_48.html

Regarding C++ preprocessor while using #define to conditionally exclude a main function

The preprocessor runs sequentially through each source file. Macros defined in one .cpp file do not affect macros defined in another .cpp file.

One option is to define FN_MAIN in the header: then when Test1.cpp includes that header the macro will still be defined. However, I think it's probably cleaner to define the macro on the command line; it depends on what your specific use case is though.

Another option would be to move the Test1.cpp main() into a separate .cpp file and build a separate executable with it.



Related Topics



Leave a reply



Submit