【C语言】宏定义
条评论实例1:
宏定义计算问题
#define PRODUCT (x) (x*x) int main() { int a,b = 3; a = PRODUCT(b+2); }
求a的值:
结果为:a = b+2*b+2=3+2*3+2=11
实例2:
描述下面XXX这个宏的作用。
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER) #define XXX(ptr,type,member)({\ const typeof(((type*)0)->member) *__mpter=(ptr);\ (type*)((type*)__mpter - offsetof(type,member));})
第一个宏:
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
(TYPE*)0
,将0强制转换为TYPE类型的指针,并且指向了0地址空间。(TYPE*)0)->MEMBER
,指向结构体中的成员&((TYPE*)0)->MEMBER
,获取成员在结构体中的位置,因为其实位置为0,所以获取的地址即为实际的偏移地址。(size_t)&((TYPE*)0)->MEMBER
,将偏移地址强制转换为size_t,即unsigned int。
(TYPE*)0 => p = (TYPE*)0
(TYPE*)0)->MEMBER => p->MEMBER
&((TYPE*)0)->MEMBER) => &(p->MEMBER) //成员MEMBER的地址
第二个宏:
#define XXX(ptr,type,member)({\
const typeof(((type*)0)->member) *__mpter=(ptr);\
(type*)((type*)__mpter - offsetof(type,member));})
({ })
的语法形式是GNU C编译器的语法扩展,与逗号表达式类似,表达式结果为最后一个语句的值。typeof
主要用于宏定义之中,可以使用typeof关键字来引用宏参数的类型。typeof(((type*)0)->member)
,引用type结构体的member成员的数据类型。const typeof(((type*)0)->member) *__mpter=(ptr);
,定义一个与type结构体的member成员相同的类型的指针变量__mpter
,而且将ptr
赋值给它。offsetof(type,member)
,获取member成员在type结构中的偏移量。(type*)((type*)__mpter - offsetof(type,member));
,将__mpter
减去偏移量,就得到了这个结构变量的地址了(指针)。
ptr是指向正被使用的某类型变量指针;
type是包含ptr指向的变量类型的结构类型;
member是type结构体中的成员,类型与ptr指向的变量类型一样;
宏定义的功能是:计算返回包含ptr指向的变量所在的type类型结构变量的指针。
实例3:
用C语言字节编写一下四个宏
ALGN_DOWN(x, a)将数值x按照a的整数倍向下取整,例如ALGN_DOWN(65,3) = 63;
ALGN_UP(x, a)将数值x按照a的整数倍向上取整,例如ALGN_UP(65,3) = 66;
ALGN_2N_DOWN(x, a)将数值x按照a的整数倍向下取整,a是2的n次幂,例如ALGN_2N_DOWN(65,4) = 64;
ALGN_2N_UP(x, a)将数值x按照a的整数倍向上取整,a是2的n次幂,例如ALGN_2N_UP(65,4) = 68。
设条件为:
int x;
int a = 8;
将数值x按照a的整数倍向下取整,a是2的n次幂:
对齐掩码a_mask = 11111 11111 11111 11111 11111 11110 00,即 ~(a- 1)
对齐掩码a_mask与a进行”与运算”就可以得到,将数值x按照a的整数倍向下取整,a是2的n次幂。
#ALGN_2N_DOWN(x, a) (x & ([~(a-1)]) )
将数值x按照a的整数倍向上取整,a是2的n次幂
如果要求出比x大的是不是需要加上a就可以了?可是如果x本身就是a的倍数,这样加a不就错了吗?
所以在x基础上加上(a - 1),然后与a的对齐掩码进行与运算。
#ALGN_2N_UP(x, a) ((x+a-1) & (~ (a-1)))
实例:
x=0, a=8, 则ALGN_2N_DOWN(x,a)=0, ALGN_2N_UP(x,a)=0.
x=6, a=8, 则ALGN_2N_DOWN(x,a)=0, ALGN_2N_UP(x,a)=8.
x=8, a=8, 则ALGN_2N_DOWN(x,a)=8, ALGN_2N_UP(x,a)=8.
x=14, a=8,则ALGN_2N_DOWN(x,a)=8, ALGN_2N_UP(x,a)=16.
注:a应当为2的n次方, 即2, 4, 8, 16, 32, 64, 128, 256, 1024, 2048, 4096 ...
参考:内核宏ALIGN的含义
实例4
用预处理指令#define声明一个常数,用以表示1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
一年的秒数为31536000,16位的int型将会溢出,因此要使用长整型符号L
实例5
写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
#define MIN(A,B) ((A)<=(B)?(A):(B))
容易错的地方:宏中间要小心地把参数用括号括起来。