C language using macros

 

Conditions of use conditional compilation macros

For example, for the same code, I want to build two different versions, where one version to remove a part of the functions,
this case can be compiled by determining whether the macro conditions, for example:
_ C language macro 1.png
if the condition is not used to control macro, want to build two different versions of the program, you need to keep tWO copies of the source code.

Conditional compilation of grammar and syntax similar if else, for example, must end with #endif:

# IF constant expression 
 // Code. 1 
# elif constant expression 
 // Code 2 
# elif constant expression 
 // Code. 3 
# the else 
  // Code. 4 
# endif

Conditions will be evaluated according to the compile-time constant expressions, constant if the expression is false, then the corresponding code will not be compiled, can also determine whether a macro definition, for example:

# Ifdef (NameOfMacro) 
     // Code. 1 
# the else
      // Code 2 
# endif

If NameOfMacro is defined, then compile the code 1 will be involved, or involved in compiling code 2, the following wording is equivalent to:

# IF defined (NameOfMacro) 
     // Code. 1 
# the else
      // Code 2 
# endif
#if !defined(NameOfMacro)
     //代码2  
#else
     //代码1
#endif

宏一般都定义在头文件中,要想使用改宏则使用#include包含该头文件即可,也可以定义在源文件中,但是这种情况比较少,一定要确保条件判断中的宏的定义位置位于条件判断之前,否则不会生效;宏的作用范围从定义它的位置开始到源文件结束,在其他源文件中该宏不可见,如果想使用某个宏,则必须使用#include指令包含对应的头文件。
除了在头文件和源文件中定义宏,还可以在定义预处理宏,
例如:在VS项目属性中
_ C language macro 2.png
预处理宏只能是空的宏,但预处理宏作用于整个工程,对该工程中任意源文件可见,优先于任何定义在源码中的宏.

使用空宏进行说明

可以使用空宏对函数参数进行说明,微软的API中就使用了空宏,例如:

   WINBASEAPI
   BOOL
   WINAPI
   WriteFileEx(
             _In_ HANDLE hFile,
             _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer,
             _In_ DWORD nNumberOfBytesToWrite,
             _Inout_ LPOVERLAPPED lpOverlapped,
             _In_ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
             );

In,_Inout_定义如下:
_ C language macro 3.png
_In_表示该参数为传入参数,Inout_表改参数为传入传出参数,为了防止_In,_Inout_被
别人定了,所以先使用#ifdef判断该宏是否被定义,如果被定义则使用#undef取消定义,然后
在重新定义该宏。

#和##运算符

除了#define 标识符 记号序列 这种形式定义宏,还可以定义带有参数的宏,形式如下:
#define 标识符(标识符列表(可选)) 记号序列,
在定义带有形参的宏定义中,#和##将会影响宏替换的过程,如果记号序列中某一个参数前
面有一个#,那么替换时将会在这个参数前后插入",将其变成一个字符串,即使该参数是
另一个带参宏,也不会在进行宏展开替换;如果该参数为一个字符串常量,那么预处理器会
分别为字符串前后的"号进行转义,将"变成字符,然后在前后各插入一个";

例:

 #define TEST0(p1) #p1"333"
 #define TEST(p1,p2,p3) #p1#p2 #p3
 int main()
 {
   int nTest1;
   int nTest2;
   int nTest3;
   printf("%s", TEST(TEST0(0),"333",nTest3));
   return 0;
 }

运行结果:
Parameterized macro definition .png

从上面的例子可以看出#运算符主要作用就是将宏定义中的参数变成字符串,而##运算符的
作用就是将宏定义中相邻的两个的参数连接在一起组成一个标识符,如果该标识符不符合C
语言表示符的组成规则,那么编译时会报错;
例如:
Parameterized macro definition 1.png

对于使用了##和#的宏定义,预处理器需要进行反复扫描分析记号序列,以此来查找已定义的
标识符进行替换,如果一个表示符在某次扫描中被替换后,再次扫描遇到此标识符时,则不在
进行替换。
例:

 #define TEST(p1,p2) p1##p2
 int main()
 {
   int nTest1;
   int nTest2;
   int nTest3;
   int TEST(TEST(nTest1, nTest2), nTest3) = 3;
   printf("%d", TEST(TEST(nTest1, nTest2), nTest3));
   return 0;
 }

Parameterized macro definition 2.png

使用/P命令查看编译预处理后的结果:
Big P command .png

 int main()
 {
   int nTest1;
   int nTest2;
   int nTest3;
   int TEST(nTest1, nTest2)nTest3 = 3;
   printf("%d", TEST(nTest1, nTest2)nTest3);
   return 0;
 }

可以看出TEST(TEST(nTest1, nTest2), nTest3)第一次展开后为TEST(nTest1, nTest2)nTest3,
然后又遇到了TEST宏定义,则不在进行展开,直接将TEST(nTest1, nTest2)nTest3作为最终结果,但是
TEST(nTest1, nTest2)nTest3显然不符合C语言表示符的定义,所以编译时会报错。

Note: After the / P command is complete, you must remove it from the command line, or compile time error will be reported can not find xxxxx.obj

# And ## operators are C language macro definition two operators are more creative, you can create a lot of "black magic" macro definitions

Predefined macros

C language some predefined macros can not cancel the definition and redefinition:
C language standard predefined macros .png

 

Guess you like

Origin www.cnblogs.com/UnknowCodeMaker/p/11101564.html
Recommended