c语言的宏定义

忘了啥时候记的笔记了

宏定义

宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译

1.不带参数的宏定义:

       宏定义又称为宏代换、宏替换,简称“宏”。 格式: #define 标识符 字符串 ,其中的标识符就是所谓的符号常量,也称为“宏名”。

       预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。 掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。 即在对相关命令或语句的含义和功能作具体分析之前就要换:

       例: #define PI 3.1415926 ,把程序中出现的PI全部换成3.1415926

说明:
       (1)宏名一般用大写
       (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
       (3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
       (4)宏定义末尾不加分号;
       (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
       (6)可以用#undef命令终止宏定义的作用域
       (7)宏定义可以嵌套
       (8)字符串" "中永远不包含宏
       (9)宏定义不分配内存,变量定义分配内存。

2.带参数的宏定义:

       除了一般的字符串替换,还要做参数代换

       格式: #define 宏名(参数表) 字符串 例如:#define S(a,b) a * b ,area=S(3,2);第一步被换为area=a*b; ,第二步被换为area = 3 * 2;

类似于函数调用,有一个哑实结合的过程:
       (1)实参如果是表达式容易出问题 ,#define S ( r ) r * r ,area=S(a+b);第一步换为area=r * r;,第二步被换为area=a+b * a+b; 正确的宏定义是#define S ( r ) (( r ) * ( r ))
       (2)宏名和参数的括号间不能有空格
       (3)宏替换只作替换,不做计算,不做表达式求解
       (4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
       (5)宏的哑实结合不存在类型,也没有类型转换。
       (6)函数只有一个返回值,利用宏则可以设法得到多个值
       (7)宏展开使源程序变长,函数调用不会
       (8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)

       

C语言宏定义技巧(常用宏定义)

       写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性

1,防止一个头文件被重复包含

#ifndef TEST_H    // 1
#define TEST_H    // 2
//.......... // 一些声明语句
#endif               // 3

       以上代码:如果没有定义TEST_H变量,就继续往下执行,如果定义了,就直接endif,即不做任何操作。

       如果一个文件中包含了两个同样的头文件,那么第一次调用这个头文件的时候,没有定义TEST_H,经过1,到达2,定义TEST_H,进行代码段的执行,到3结束。但是当第二次调用头文件时,已经定义了TEST_H,所以就不会进行下面的代码声明了。这就是条件编译进行防止头文件包含的原理

#define后面只要写个"文件名"保证其是一个独一无二的定义就可以了

2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。

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 */ 

       当时写单片机的时候常用这东西。

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

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

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

        这东西我没咋用过。倒是当年写汇编的时候会直接对内存地址进行操作,c我没这么用过,主要是不知道确切地址,

4,求最大值和最小值

#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) ) 

#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) ) 

        三目运算符代替函数,算是常用的一个操作。

5,得到一个变量的地址(word宽度)

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

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

6,得到一个字的低位和高位字节

#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255)) //得到低位

#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8)) //得到高位

7,将一个字母转换为大写

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

        当时比较菜

8,返回数组元素的个数

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

        也是个常用的方法,大一的时候比较菜,投机取巧嘛

9,宏定义防止使用是错误

        用小括号包含。例如

#define ADD(a,b) (a+b) 

        可以看到上面的一些宏定义看上去有些是不必要的小括号,其实都是一次次试出来的,都是必要的

猜你喜欢

转载自blog.csdn.net/qq_43657442/article/details/108065060
今日推荐