宏定义
预处理器直接对宏进行文本替换,宏使用时的参数不会进行求值和运算,预处理器不会对宏定义进行语法检查
#define 定义的宏可以出现在程序的任意位置
#define 定义之后的代码都可以使用这个宏(没有作用域限制)
#define 表达式的使用类似函数调用 #define _DIM_(a) sizeof(a)/sizeof(*a)
强大的内置宏 __FILE__ __LINE__ __DATE__ __TIME__
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)
条件编译
实际工程中条件编译主要应用于:不同产品线共用一份代码。区分编译产品的调试版和发布版。
条件编译是预处理指令命令,用于控制是否 编译 某段代码
预编译器根据条件编译指令有选择的删除代码
编译器不知道代码分支的存在
可以通过命令行定义宏 gcc -Dmacro=value file.c或者gcc -Dmacro file.c
/**************************************************/
#define C 1
int main()
{
#if(C == 1)
printf(" 1 \n");
#else
printf(" 2 \n");
#endif
return 0;
}
/************************************************/
int main()
{
#ifdef C
printf(" 1 \n");
#else
printf(" 2 \n");
#endif
return 0;
}
/***************************************************/
解决头文件重复包含的编译错误
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
//source code
#endif
/**************************************************/
//条件编译的工程应用
//a.h
#define DEBUG 1
#define HIGH 1
//a.c
#include <stdio.h>
#include "product.h"
#if DEBUG
#define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)
#else
#define LOG(s) NULL
#endif
#if HIGH
void f()
{
printf("This is the high level product!\n");
}
#else
void f()
{
}
#endif
int main()
{
LOG("Enter main() ...");
f();
printf("1. Query Information.\n");
printf("2. Record Information.\n");
printf("3. Delete Information.\n");
#if HIGH
printf("4. High Level Query.\n");
printf("5. Mannul Service.\n");
printf("6. Exit.\n");
#else
printf("4. Exit.\n");
#endif
LOG("Exit main() ...");
return 0;
}
#error的用法
#error message message不需要被双引号包围
#error 编译指示字用于自定义程序员特有的编译错误消息
类似的, #warning 用于生成编译警告(可以生成可执行文件,#error 不能生成可执行文件)
#ifndef __cplusplus
#error This file should be processed with C++ compiler
#endif
/***************************************************/
#include <stdio.h>
void f()
{
#if ( PRODUCT == 1 )
printf("This is a low level product!\n");
#elif ( PRODUCT == 2 )
printf("This is a middle level product!\n");
#elif ( PRODUCT == 3 )
printf("This is a high level product!\n");
#else
#error the "PRODUCT " is not defined!
#endif
}
int main()
{
f();
printf("1. Query Information.\n");
printf("2. Record Information.\n");
printf("3. Delete Information.\n");
#if ( PRODUCT == 1 )
printf("4. Exit.\n");
#elif ( PRODUCT == 2 )
printf("4. High Level Query.\n");
printf("5. Exit.\n");
#elif ( PRODUCT == 3 )
printf("4. High Level Query.\n");
printf("5. Mannul Service.\n");
printf("6. Exit.\n");
#else
#error the "PRODUCT " is not defined!
#endif
return 0;
}
/********************************************************/
#pragma
#pragma 用于指示编译器完成一些特定的动作
#pragma 所定义的很多指示字都是编译器特有的
#pragma 在不同的编译器是不可以移植的
预处理器将忽略他不认识的#pragma指令
一般用法 #pragma parameter
示例:
/*******************************************/
#include <stdio.h>
#if defined(ANDROID20)
#pragma message("Compile Android SDK 2.0...")
#define VERSION "Android 2.0"
#elif defined(ANDROID23)
#pragma message("Compile Android SDK 2.3...")
#define VERSION "Android 2.3"
#elif defined(ANDROID40)
#pragma message("Compile Android SDK 4.0...")
#define VERSION "Android 4.0"
#else
#error Compile Version is not provided!
#endif
int main()
{
printf("%s\n", VERSION);
return 0;
}
/********************************************/
#pragma once
#pragma once用于保证头文件被编译一次,效率比较高,但是它是编译器相关的,不一定被支持
最佳使用方法
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
#pragma once
//source code
#endif
#pragma pack
#运算符
#运算符用于预处理期间将宏参数转换为字符串
#的转换作用是在预处理期完成的,因此只在宏定义中有效
编译器不知道#的转换作用
用法
#define STRING(x) #x
printf("%s",STRING(hello world!\n));
工程应用
/********************************************/
#include <stdio.h>
#define CALL(f, p) (printf("Call function %s\n", #f), f(p))
int square(int n)
{
return n * n;
}
int func(int x)
{
return x;
}
int main()
{
int result = 0;
result = CALL(square, 4);
printf("result = %d\n", result);
result = CALL(func, 10);
printf("result = %d\n", result);
return 0;
}
/*******************************************************/
##运算符
##运算符用于在预处理器粘连两个标识符
##的转换作用是在预处理期完成的,因此只在宏定义中有效
编译器不知道##的连接作用
用法
#define CONNECT(a,b) a##b
int CONNECT(a,1); //int a1;
工程应用
/****************************************************/
#include <stdio.h>
#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type
STRUCT(Student)
{
char* name;
int id;
};
int main()
{
Student s1;
Student s2;
s1.name = "s1";
s1.id = 0;
s2.name = "s2";
s2.id = 1;
printf("s1.name = %s\n", s1.name);
printf("s1.id = %d\n", s1.id);
printf("s2.name = %s\n", s2.name);
printf("s2.id = %d\n", s2.id);
return 0;
}
/***********************************************************/
预处理器直接对宏进行文本替换,宏使用时的参数不会进行求值和运算,预处理器不会对宏定义进行语法检查
#define 定义的宏可以出现在程序的任意位置
#define 定义之后的代码都可以使用这个宏(没有作用域限制)
#define 表达式的使用类似函数调用 #define _DIM_(a) sizeof(a)/sizeof(*a)
强大的内置宏 __FILE__ __LINE__ __DATE__ __TIME__
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG(s) printf("[%s] {%s:%d} %s \n", __DATE__, __FILE__, __LINE__, s)
条件编译
实际工程中条件编译主要应用于:不同产品线共用一份代码。区分编译产品的调试版和发布版。
条件编译是预处理指令命令,用于控制是否 编译 某段代码
预编译器根据条件编译指令有选择的删除代码
编译器不知道代码分支的存在
可以通过命令行定义宏 gcc -Dmacro=value file.c或者gcc -Dmacro file.c
/**************************************************/
#define C 1
int main()
{
#if(C == 1)
printf(" 1 \n");
#else
printf(" 2 \n");
#endif
return 0;
}
/************************************************/
int main()
{
#ifdef C
printf(" 1 \n");
#else
printf(" 2 \n");
#endif
return 0;
}
/***************************************************/
解决头文件重复包含的编译错误
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
//source code
#endif
/**************************************************/
//条件编译的工程应用
//a.h
#define DEBUG 1
#define HIGH 1
//a.c
#include <stdio.h>
#include "product.h"
#if DEBUG
#define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s)
#else
#define LOG(s) NULL
#endif
#if HIGH
void f()
{
printf("This is the high level product!\n");
}
#else
void f()
{
}
#endif
int main()
{
LOG("Enter main() ...");
f();
printf("1. Query Information.\n");
printf("2. Record Information.\n");
printf("3. Delete Information.\n");
#if HIGH
printf("4. High Level Query.\n");
printf("5. Mannul Service.\n");
printf("6. Exit.\n");
#else
printf("4. Exit.\n");
#endif
LOG("Exit main() ...");
return 0;
}
#error的用法
#error message message不需要被双引号包围
#error 编译指示字用于自定义程序员特有的编译错误消息
类似的, #warning 用于生成编译警告(可以生成可执行文件,#error 不能生成可执行文件)
#ifndef __cplusplus
#error This file should be processed with C++ compiler
#endif
/***************************************************/
#include <stdio.h>
void f()
{
#if ( PRODUCT == 1 )
printf("This is a low level product!\n");
#elif ( PRODUCT == 2 )
printf("This is a middle level product!\n");
#elif ( PRODUCT == 3 )
printf("This is a high level product!\n");
#else
#error the "PRODUCT " is not defined!
#endif
}
int main()
{
f();
printf("1. Query Information.\n");
printf("2. Record Information.\n");
printf("3. Delete Information.\n");
#if ( PRODUCT == 1 )
printf("4. Exit.\n");
#elif ( PRODUCT == 2 )
printf("4. High Level Query.\n");
printf("5. Exit.\n");
#elif ( PRODUCT == 3 )
printf("4. High Level Query.\n");
printf("5. Mannul Service.\n");
printf("6. Exit.\n");
#else
#error the "PRODUCT " is not defined!
#endif
return 0;
}
/********************************************************/
#pragma
#pragma 用于指示编译器完成一些特定的动作
#pragma 所定义的很多指示字都是编译器特有的
#pragma 在不同的编译器是不可以移植的
预处理器将忽略他不认识的#pragma指令
一般用法 #pragma parameter
示例:
/*******************************************/
#include <stdio.h>
#if defined(ANDROID20)
#pragma message("Compile Android SDK 2.0...")
#define VERSION "Android 2.0"
#elif defined(ANDROID23)
#pragma message("Compile Android SDK 2.3...")
#define VERSION "Android 2.3"
#elif defined(ANDROID40)
#pragma message("Compile Android SDK 4.0...")
#define VERSION "Android 4.0"
#else
#error Compile Version is not provided!
#endif
int main()
{
printf("%s\n", VERSION);
return 0;
}
/********************************************/
#pragma once
#pragma once用于保证头文件被编译一次,效率比较高,但是它是编译器相关的,不一定被支持
最佳使用方法
#ifndef _HEADER_FILE_H_
#define _HEADER_FILE_H_
#pragma once
//source code
#endif
#pragma pack
#运算符
#运算符用于预处理期间将宏参数转换为字符串
#的转换作用是在预处理期完成的,因此只在宏定义中有效
编译器不知道#的转换作用
用法
#define STRING(x) #x
printf("%s",STRING(hello world!\n));
工程应用
/********************************************/
#include <stdio.h>
#define CALL(f, p) (printf("Call function %s\n", #f), f(p))
int square(int n)
{
return n * n;
}
int func(int x)
{
return x;
}
int main()
{
int result = 0;
result = CALL(square, 4);
printf("result = %d\n", result);
result = CALL(func, 10);
printf("result = %d\n", result);
return 0;
}
/*******************************************************/
##运算符
##运算符用于在预处理器粘连两个标识符
##的转换作用是在预处理期完成的,因此只在宏定义中有效
编译器不知道##的连接作用
用法
#define CONNECT(a,b) a##b
int CONNECT(a,1); //int a1;
工程应用
/****************************************************/
#include <stdio.h>
#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type
STRUCT(Student)
{
char* name;
int id;
};
int main()
{
Student s1;
Student s2;
s1.name = "s1";
s1.id = 0;
s2.name = "s2";
s2.id = 1;
printf("s1.name = %s\n", s1.name);
printf("s1.id = %d\n", s1.id);
printf("s2.name = %s\n", s2.name);
printf("s2.id = %d\n", s2.id);
return 0;
}
/***********************************************************/