C语言进阶 - 玩转宏定义

C语言的编程过程中经常会用到宏定义,然而如果你只是使用宏定义做一些常量的定义,那么你不是OUT了就是C语言小白。下面我们一起来看一下在编程过程中,宏定义都有哪些作用。

  1. 常量定义
  2. 可以作为功能代码的开关
  3. 防止头文件被重复包含
  4. 定义一些通用类型,防止因为平台和编译器不同导致的类型差异,方便移植
  5. 其他高级浮夸用法

好了,各位看官一起来看一下使用的例子吧

一. 常量定义

#define PI 3.1415926 //定义π值,代码易读

#define MAX_LEN 1024 //定义常数,不像const修饰的变量要占用空间

二.防止头文件重复包含

#ifndef  COMDEF_H

#define  COMDEF_H

//头文件内容

#endif

三.重定义数据类型,方便移植

typedef unsigned char boolean; /* Boolean value type. */

typedef unsigned long int uint32; /* Unsigned 32 bit value */

typedef unsigned short uint16; /* Unsigned 16 bit value */

typedef unsigned char uint8; /* Unsigned 8 bit value */

typedef signed long int int32; /* Signed 32 bit value */

typedef signed short int16; /* Signed 16 bit value */

typedef signed char int8; /* Signed 8 bit value */

四. 宏函数

#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) //请注意这里的括号,一定
                             //要加,否则会有意外惊喜
                                          //加括号都不是最完美的

//宏定义实现一个参数交换

#define SWAP(X, Y) \
X = X +Y; \
Y = X - Y; \
X = X - Y;

//再来看一下求数组的最大最小值是不是非常简洁
maxvalue =minvalue = a[0];
for(i = 1; i < MAXLEN; i++)
{
    maxvalue = MAX(maxvalue, a[i]);
    minvalue = MIN(minvalue , a[i]);
}

五. 作为开关使用

#ifdef DEBUG_MODE //在调试模式下(DEBUG_MODE在之前被定义)才会将代码编译进去
……
#endif
#if (KEY_ON) //可以根据宏定义KEY_ON的真假来选择代码进行编译
……
#else
……
#endif

六. 作为字符串或者连字符使用

  在宏体中,如果宏体所在标示符中有##,那么在宏体扩展的时候,宏参数会被直接替换到标示符中如:

#define COMMAND(NAME) { #NAME, NAME ## _command }
struct command
{
    char *name;
    void (*function) (void);
};

在宏扩展的时候

struct command commands[] =
{
    COMMAND (quit),
    COMMAND (help),
    ...
};

会被扩展成:

struct command commands[] =
{
    { "quit", quit_command },
    { "help", help_command },
    ...
};

七.协助调试的宏定义

__LINE__ 及 __FILE__ 宏指示,#line指令可以改变它的值,简单的讲,编译时,它们包含程序的当前行数和文件名 

__DATE__ 宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。

__TIME__ 宏指令包含程序编译的时间时间用字符串表示,其形式为 时: 分:秒

__STDC__ 宏指令的意义是编译时定义的一般来讲,如果__STDC__已经定义,编译器将仅接受不包含任何非标准扩展的标准C/C++代码。如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的

八. 其他巧用特殊宏定义

例1. 作为块注释,非常的好用,对于一些编辑器,还会自动变灰,方便阅读

#if 0

/*your code, want not use*/

#endif

例2. 宏定义连接字符串

#define MAINVER 2
#define SUBVER1 0
#define SUBVER2 1
#define STR(s) #s

#define VERSION(a,b,c) \
"System V" STR(a) "." STR(b) "." STR(c) " "__DATE__
//合并为 "System V2.0.1.2017.9.13"

例3. 得到指定地址上的一个字节或字

#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )

例4. 得到一个field在结构体(struct)中的偏移量

#define  FPOS( type, field )   ( (dword) &(( type *) 0)-> field )

例6. 得到一个结构体中field所占用的字节数

#define FSIZ( type, field ) sizeof( ((type *) 0)->field )

例7. 按照LSB格式把两个字节转化为一个Word

#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )

例8.按照LSB格式把一个Word转化为两个字节

#define FLOPW( ray, val ) \

(ray)[0] = ((val) / 256); \

(ray)[1] = ((val) & 0xFF)

例9.得到一个变量的地址(word宽度)

#define B_PTR( var ) ( (byte *) (void *) &(var) )

#define W_PTR( var ) ( (word *) (void *) &(var) )

例10.得到一个字的高位和低位字节

#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))

#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))

例11. 返回一个比X大的最接近的8的倍数

#define RND8( x ) ((((x) + 7) / 8 ) * 8 )

例12. 将一个字母转换为大写

#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )

例13. 判断字符是不是10进值的数字

#define DECCHK( c ) ((c) >= '0' && (c) <= '9')

例14. 判断字符是不是16进值的数字

#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\

((c) >= 'A' && (c) <= 'F') ||\

((c) >= 'a' && (c) <= 'f') )

例15. 防止溢出的一个方法

#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))

例16. 返回数组元素的个数

#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值