What use cases require #define without a token string?

I ran into the #define preprocessor directive before learning C, and then ran into it in some code that I read. But, besides using it for certain permutations for constants and for defining macros, I really don’t understand the specific case when it is used without a “body” or a token string.

Take, for example, this line:

 #define OCSTR(X) 

Just! What could be the use of this or better when this use of #define necessary?

+5
source share
8 answers

This is used in two cases. The first and most common conditional compilation:

 #ifndef XYZ #define XYZ // ... #endif 

You probably used this to turn on the guards, but it can also be used for things like system dependencies:

 #ifdef WIN32 // Windows specific code here... #endif 

(In this case, WIN32 is most likely defined on the command line, but it can also be defined in the "config.hpp" file.) These typically include "config.hpp" -like objects (without a list of arguments or parentheses).

The second result will be the result of conditional compilation. Something like:

 #ifdef DEBUG #define TEST(X) text(X) #else #define TEST(X) #endif 

This allows you to write things like:

 TEST(X); 

which is called by the function if DEBUG defined and does nothing if it is not.

+6
source

Such a macro usually appears in pairs and inside the conditional #ifdef as:

 #ifdef _DEBUG #define OCSTR(X) #else #define OCSTR(X) SOME_TOKENS_HERE #endif 

Another example:

 #ifdef __cplusplus #define NAMESPACE_BEGIN(X) namespace X { #define NAMESPACE_END } #else #define NAMESPACE_BEGIN(X) #define NAMESPACE_END #endif 
+3
source

One odd case that I recently dug up to answer a question turned out to be just a comment in nature. This code looked like this:

 void CLASS functionName(){ // // // } 

I found that it was just an empty #define , which the author decided to write that the function had access to global variables in the project:

C ++ syntax: void CLASS functionName ()?

So it’s not quite as if he said /* CLASS */ , except that he didn’t allow typos like /* CLAAS */ ... some other small advantages, maybe (?)

+2
source

This can be used when you can disable some features. For example, in debug mode, you want to print some debug statements in the production code that you want to omit:

 #ifdef DEBUG #define PRINT(X) printf("%s", X) #else #define PRINT(X) // <----- silently removed #endif 

Using:

 void foo () { PRINT("foo() starts\n"); ... } 
0
source

#define macros are simply replaced literally with their replacement text during preprocessing. If there is no replacement text, then ... they are replaced by nothing! So this source code:

 #define FOO(x) print(FOO(hello world)); 

will be pre-processed only as follows:

 print(); 

This can be useful to get rid of things you don't want, such as assert() . This is mainly useful in conditional situations, when under certain conditions there is a non-empty body there.

0
source

As you can see in the answers above, this can be useful when debugging your code.

 #ifdef DEBUG #define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr) #else #define debug(msg) #endif 

So, when you are debugging, the function will print the line number and file name so that you know if there is an error. And if you don’t debug, it just won’t give out an output

0
source

There are many uses for such a thing.

For example, one for a macro has different behavior in different assemblies. For example, if you want debugging messages, you might have something like this:

 #ifdef _DEBUG #define DEBUG_LOG(X, ...) however_you_want_to_print_it #else #define DEBUG_LOG(X, ...) // nothing #endif 

Another option would be to customize your header file based on your system. This is from my mesa-implemented OpenGL header in linux:

 #if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__)) # if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft compilers */ # define GLAPIENTRY # else # define GLAPIENTRY __stdcall # endif #elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */ # define GLAPIENTRY __stdcall #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 # define GLAPIENTRY #endif /* WIN32 && !CYGWIN */ #ifndef GLAPIENTRY #define GLAPIENTRY #endif 

And used in header declarations, for example:

 GLAPI void GLAPIENTRY glClearIndex( GLfloat c ); GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ); GLAPI void GLAPIENTRY glClear( GLbitfield mask ); ... 

(I removed the part for GLAPI )

Thus, you get an image, a macro that is used in some cases and not used in other cases, can be defined by something in these cases and nothing for other cases.

Other cases may include:

If the macro does not accept parameters, it may just be a declaration of some case. A well-known example is the protection of header files. Another example might be something like this.

 #define USING_SOME_LIB 

and then can be used as follows:

 #ifdef USING_SOME_LIB ... #else ... #endif 

Maybe the macro was used at a certain stage to do something (for example, a log), but then at release the owner decided that the log was no longer useful, and simply deleted the contents of the macro so that it became empty. This is not recommended, but use the method that I mentioned at the very beginning of the answer.

Finally, it can only be for a more detailed explanation, for example, you can say

 #define DONT_CALL_IF_LIB_NOT_INITIALIZED 

and you write functions like:

 void init(void); void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED; 

Although this last case is a little absurd, but it makes sense in this case:

 #define IN #define OUT void function(IN char *a, OUT char *b); 
0
source

I agree with each answer, but I would like to note a small trifle.

As a C-purist, I grew up with the statement that EACH AND EVERY #define should be an expression, so even if this is a common practice:

 #define WHATEVER 

and test it with

 #ifdef WHATEVER 

I think it's always better to write:

 #define WHATEVER (1) 

also #debug macros should be expressions:

 #define DEBUG (xxx) (whatever you want for debugging, value) 

Thus, you are completely protected from the misuse of #macros and prevent unpleasant problems (especially in a project with 10 million lines of C)

0
source

Source: https://habr.com/ru/post/951098/


All Articles