C Preprocessor, jumping out of #ifdef - c

I am currently learning C and I came across this question I can't find an answer to.
Can I jump out of a #ifdef without going through the #endif?
For example can I do this:
char getOS( void ) {
/* Returns the user Operating System
*/
#ifdef _WIN32
return 'w';
#elif TARGET_OS_MAC
return 'm';
#elif __linux__
return 'l';
#else
raiseError( "You cannot play on this OS", true );
#endif
}

I believe you are misunderstanding the preprocessor a bit. Remember, the preprocessor runs before the compiler. So this function is going to look like one of the following when it gets to the compiler:
char getOS( void ) {
return 'w';
}
char getOS( void ) {
return 'm';
}
char getOS( void ) {
return 'l';
}
char getOS( void ) {
raiseError( "You cannot play on this OS", true );
}
... and these are all valid. Well I don't know what raiseError does, but if it isn't a macro that returns or exits, you will want to add an extra return to the end of the function for the #else branch.
The point is, none of that #if, #elif, etc is going to the compiler anyway, so you are never "jumping out". If you want to see for yourself, you can add a compiler option to only do preprocessing (and no compiling). I know for gcc, that option is -E.

If by "jump out of", you mean cause the compiler to give an error, you can do that with the #error directive.
#ifdef _WIN32
return 'w';
#elif TARGET_OS_MAC
return 'm';
#elif __linux__
return 'l';
#else
#error "You cannot play on this OS"
#endif

You seem to be confusing preprocessor with runtime behavior: they are not the same.
The preprocessor runs before the actual compiler (at least conceptually; in practice they can very well be the same program of course). It affects the source that the compiler then sees.
You cannot "go through" the #endif, it's not there when the program runs. You will either have a return, or a call to raiseError().

Related

In C macros, where does the function named defined() come from?

In the code below, I don't understand the defined() function used inside #if; where is it defined?
Can anyone point me to a good resource in C language, where I could go deeper in these kinds of kinds of stuff?
#include <stdio.h>
#define Macro 7
void initMSP(void){
printf("OKay with MSP platform\n");
}
void initKine(void){
printf("Done with Kine\n");
}
//#define KINETICS
#define MSP
int main(){
printf("Hello world program\n");
printf("%d\n",Macro);
#if defined(KINETICS) && !defined(MSP)
initKine();
#elif defined(MSP) && !defined(KINETICS)
initMSP();
#else
#error "Please define a Platform "
#endif
}
defined is not a function. It is a syntactic construct of the C preprocessor, just like #define, #ifdef, and so forth. The C language proper (to the extent that you can divorce C from its preprocessor) never directly interacts with defined. It exists during preprocessing and that's that.

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.

Unused var in non-debug configuration

I often write code like this:
int result = someMethod(arg1,arg2,...);
assert(result==0)
Let's say assert() is defined something like this:
#ifdef DEBUG
#define assert(e) if(!e) printf("something's wrong");
#else
#define assert(...)
#endif
The first piece of code would give a warning about 'result' being an unused var.
I could do something like:
#ifdef DEBUG
int result = someMethod(arg1,arg2,...);
#else
someMethod(arg1,arg2,...);
#endif
assert(result==0)
But that seems quite non-dry to me ...
What else could I do?
int result = someMethod(arg1,arg2,...);
assert(result==0);
(void)result;
A macro like assertion_code to enable certain code pieces only in debug configuration.
#if defined(NDEBUG)
#define assertion_code(v)
#else
#define assertion_code(v) v
#endif
Now you can write
assertion_code(int result =) expr();
assert(result == 0);
Whitespace and line breaks are irrelevant to the compiler, so...
#ifdef DEBUG
int result =
#endif
someMethod(arg1,arg2,...);
assert(result==0)
There is the explicit way:
static inline void debug(const char *msg)
{
#ifdef DEBUG
printf("%s\n", msg);
#else
(void)msg;
#endif
}
Then:
if (someMethod(arg1,arg2,...) != 0) {
debug(message);
}
As there is a fair chance you won't want to continue as normal when something is wrong, the explicit conditional clause is perhaps going to be useful anyway. Or were you planning to ignore errors when DEBUG is turned off?

Function macro that evaluates to zero and can be used as a statement

We have a function macro #define FOO(arg) foo(arg) with int foo(const char* bar);. When NDEBUG is defined FOO is defined as #define FOO(arg) 0, however this causes many compiler warnings because in many cases FOO's return value is not used. The solution should work with with ANSI C compilers and cause no warnings. I've tried:
(void)0: can't be assigend to variable
static int foo(const char* bar) { return 0; } : causes unused static function warning in some modules
static inline int foo(const char* bar) { return 0; } : only works with C99 compilers
Thanks for your help!
edit1:
It's somewhat like a trace macro and used all over the project. Mostly it's just used as a statement like FOO("function x called");, but in a few cases I saw if (FOO("condition a")) { /* some more debug output */ }. With NDEBUG defined and optimization enabled nothing should be left of FOO. I didn't come up with this, but I have to clean up this mess :).
edit2: I should add that for gcc release builds these flags are used: -O3 -Wall -ansi
edit3: For now I'm going with __inline int dummy() { return 0; }. __inline works with both VisualC and GCC in ansi mode.
I guess it's a little bit compiler dependent but this should work:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) ((int)0)
#endif
It prevents the "expression has no effect" warning, it does nothing and its value when used is still 0.
EDITED
It seems it's something not so portable so (now) you have these conditions:
(0) or ((int)0) work at least on VC 2010.
__noop should work on any version of VC after 2003.
VC6 is not a problem because it doesn't emit the C4555 warning at all. For other compilers you may use:
((void)0, 0) It may work on a lot of compilers (maybe it's the more portable one?).
inline int foo(const char* bar) { return 0; } works with any other C99 compiler (as you wrote you may need to declare it as static on gcc).
For any other prehistoric C compiler use the solution pointed by #Jobs: abs(0)
What you could do to prevent the warning is the following:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) abs(0)
#endif
I'm not saying this is ideal (you'd have to make sure stdlib.h is included everywhere, for example) but it does prevent the warning.
I'd do something that is dependent on the C version. In the header file:
#if __STDC_VERSION__ > 199900L
inline int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif
in one compilation unit
#if __STDC_VERSION__ < 199900L
int foo(const char* bar) { return 0; }
#else
int foo(const char* bar);
#endif
or use for the oldish C version something like Job's answer, that is a function that is certain to be optimized out but that doesn't produce the warning.

Return with Macro C programming

This code is always returning -1 even when the fopen() function has executed successfully. Is there something I am ignoring.
void nullCheck(FILE* checkVar) {
if(checkVar==NULL) {
#define _NULL_ERROR
}
}
int readFile(char* _name, char* storeArray) {
FILE* fp;
fp=fopen(_name,READ_ONLY_MODE);
nullCheck(fp);
#ifndef _NULL_ERROR
char c=0;
while((c=getc(fp))!=EOF) {
*(storeArray+i)=c;
i+=1;
}
#endif
#ifdef _NULL_ERROR
#undef _NULL_ERROR
return -1;
#endif
return 1;
}
Thanks!
Oy va voy! Macros are defined and undefined when your code is compiled, not when it runs! They are not affected by control flow statements like "if" and "then" -- they are all processed before compilation of those statements even begins!
You need to re-read the documentation on the C Preprocessor. The #define _NULL_ERROR doesn't get executed when nullCheck is called, it gets interpeted when the preprocessor processes the file before it is compiled. So you are always setting _NULL_ERROR and so you will always return -1.
#define is a preprocessor command, which means it's not calculated / processed in the function nullCheck() but before the compiling of the code. so _NULL_ERROR is always defined and therefore the condition
#ifdef _NULL_ERROR
#undef _NULL_ERROR
return -1;
#endif
will always cause the pre-compiler to add the return -1; to your code.
This is what your code looks like to the compiler, after the preprocessor runs:
void nullCheck(FILE* checkVar) {
if(checkVar==NULL) {
}
}
int readFile(char* _name, char* storeArray) {
FILE* fp;
fp=fopen(_name,READ_ONLY_MODE);
nullCheck(fp);
return -1;
return 1;
}
As has been stated above, the preprocessor deals with macros before the compiler runs.
#define, #ifdef, and friends don't work like you think they do. They're preprocessor directives that affect your code even before the compiler sees it. Get your compiler to show you the preprocessed source before it compiles (-E or -save_temps in gcc and clang) and you'll immediately see what's going on.

Resources