define普通用法

1.1 定义常量

1
#define PI 3.1415

1.2 定义简单函数

1
#define MAX(a,b) (a>b ? a : b)

1.3 避免重复定义

1
2
3
4
#ifndef VEHICLE_H
#define VEHICLE_H
//
#endif

define高级用法

2.1 define中的三个特殊符号:#,##,#@

字符串化(stringizing) [#]

将传入的参数名转换为用一对双引号引用的字符串。

1
2
3
4
#define StrFormat(x) #x  

//s1 = StrFormat( 1024 ); // s1="1024"
//s2 = StrFormat(ab cd ef); // s2="ab cd ef"
  • 传入参数前面和后面的空格会被忽略。
  • 传入参数中间存在空格,编译器将各个子字符串之间用一个空格连接。

符号连接(token-pasting)[##]

将宏定义中的多个参数连接形成一个参数。

1
2
3
4
5
#define Cat(x,y) x##y

//Cat(abc,123) // abc123
//int n = Conn(123,456); // n=123456;
//char* str = Conn("asdf", "adf"); // str = "asdfadf"

字符化(charizing)[#@]

将传入的单字符参数名转换为字符。

1
2
3
#define CH(x) #@x

//char a = CH(1); //a='1'

多行定义[\]

当定义的宏不能用一行表达完整时,可以用 \ 表示下一行继续此宏的定义。

1
2
3
4
5
6
#define switch(a,b) do { \
int t = 0; \
t = a; \
a = b; \
b = t; \
} while(0)

do{}while(0)

将宏用 do{}while(0) 将宏包裹起来使其成为一个独立的语法单元,从而不会与上下文发生混淆,同时大部分编译器能够识别 do{}while(0) 这种无用的循环,并对其进行优化,所以使用这种方法不会导致性能的降低。

主要应用于下面三种情况:

  • 空的宏定义,避免Warning。
  • 复杂逻辑,需要一个独立的block。
  • 宏用在判断语句之后。

为什么不用{}?

1
2
3
4
5
6
#define switch(a,b) {int t = 0; t = a; a = b; b = t;}

if (x > y)
switch(x,y);
else //出现编译错误,宏引入代码后多一个分号
//todo

2.2 标准预定义宏

  • __LINE__:在源代码中插入当前源代码行号;
  • __FILE__:在源文件中插入当前源文件名;
  • __DATE__:在源文件中插入当前的编译日期
  • __TIME__:在源文件中插入当前编译时间;
  • __STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1;
  • __cplusplus:当编写C++程序时该标识符被定义。

2.3 可变参数宏

1
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

如果可变参数被忽略或为空,’##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。

TDM 项目中用到的宏

3.1 平台宏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Android: __ANDROID__
//WINDOWS: __WINDOWS__ (Win32 + Win64)
//Win32: _WIN32
//Win64: _WIN64
//Apple: __APPLE__ (Mac + iOS)
//Mac: _MAC
//iOS: _IOS

#if defined(_WIN32) || defined(_WIN64)
#define __WINDOWS__
#elif defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_OS_IOS || TARGET_OS_IPHONE
#define _IOS
#else
#define _MAC
#endif
#elif defined(__ANDROID__)
#define _AOS
#endif

3.2 字节序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#if defined(_WIN32) || defined(_WIN64)
#if defined (LITTLEENDIAN) && (LITTLEENDIAN > 0)
#define A_OS_LITTLEENDIAN
#else
#define A_OS_BIGENDIAN
#endif
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define A_OS_LITTLEENDIAN
#else
#define A_OS_BIGENDIAN
#endif
#endif

#if (defined(_WIN32) || defined(_WIN64))
#define A_OS_SWAP64(x) \
( (((x) & (uint64_t)0xff00000000000000) >> 56) \
| (((x) & (uint64_t)0x00ff000000000000) >> 40) \
| (((x) & (uint64_t)0x0000ff0000000000) >> 24) \
| (((x) & (uint64_t)0x000000ff00000000) >> 8) \
| (((x) & (uint64_t)0x00000000ff000000) << 8) \
| (((x) & (uint64_t)0x0000000000ff0000) << 24) \
| (((x) & (uint64_t)0x000000000000ff00) << 40) \
| (((x) & (uint64_t)0x00000000000000ff) << 56))
#else
#define A_OS_SWAP64(x) \
( (((x) & (uint64_t)0xff00000000000000LL) >> 56) \
| (((x) & (uint64_t)0x00ff000000000000LL) >> 40) \
| (((x) & (uint64_t)0x0000ff0000000000LL) >> 24) \
| (((x) & (uint64_t)0x000000ff00000000LL) >> 8) \
| (((x) & (uint64_t)0x00000000ff000000LL) << 8) \
| (((x) & (uint64_t)0x0000000000ff0000LL) << 24) \
| (((x) & (uint64_t)0x000000000000ff00LL) << 40) \
| (((x) & (uint64_t)0x00000000000000ffLL) << 56))
#endif /* #if (defined(_WIN32) || defined(_WIN64)) */

#define A_OS_SWAP32(x) \
( (((x) & 0xff000000) >> 24) \
| (((x) & 0x00ff0000) >> 8) \
| (((x) & 0x0000ff00) << 8) \
| (((x) & 0x000000ff) << 24))

#define A_OS_SWAP16(x) \
( (((x) & 0xff00) >> 8) \
| (((x) & 0x00ff) << 8))


// ntoh & hton
#ifdef A_OS_LITTLEENDIAN
#define a_ntoh64(x) A_OS_SWAP64(x)
#define a_hton64(x) A_OS_SWAP64(x)
#define a_ntoh32(x) A_OS_SWAP32(x)
#define a_hton32(x) A_OS_SWAP32(x)
#define a_ntoh16(x) A_OS_SWAP16(x)
#define a_hton16(x) A_OS_SWAP16(x)
#else
#define a_ntoh64(x) (x)
#define a_hton64(x) (x)
#define a_ntoh32(x) (x)
#define a_hton32(x) (x)
#define a_ntoh16(x) (x)
#define a_hton16(x) (x)
#endif

3.3 符号导出

1
2
3
4
5
6
7
8
9
10
11
12
13
#if defined(_WIN32) || defined(_WIN64)
#ifdef TDM_BUILD
#define TDM_EXPORT __declspec(dllexport)
#else
#define TDM_EXPORT __declspec(dllimport)
#endif
#else
#if __GNUC__ >= 4
#define TDM_EXPORT __attribute__ ((visibility ("default")))
#else
#define TDM_EXPORT
#endif
#endif

查看编译器预定义的宏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# C编译(方法1)
gcc -dM -E - < /dev/null
gcc -dM -E -include sys/socket.h - < /dev/null

# C编译(方法2)
echo | gcc -dM -E -
echo "#include <sys/socket.h>" | gcc -E -dM -

# C++编译(方法1)
g++ -dM -E -x c++ -std=c++11 < /dev/null
g++ -dM -E -x c++ -std=c++11 -include sys/socket.h - < /dev/null

# C++编译(方法2)
echo | gcc -x c++ -std=c++11 -dM -E -
echo "#include <stdlib.h>" | gcc -x c++ -std=c++11 -dD -E -

参考文档:
http://huqunxing.site/2016/11/14/C++%20define%20%E4%B8%AD%E7%9A%84%E7%89%B9%E6%AE%8A%E7%AC%A6%E5%8F%B7/