1.常用的位运算操作
设置/清零、取反某些位
对某一位置 1,需要用和 1 按位或的方法;
对某一位置 0,需要用和 0 按位与的方法;
对某一位翻转,需要用和 1 按位异或的方法;
使用宏定义实现的方法如下:
#define setbit(x,y) x |= (1 << y)
#define clrbit(x,y) x &= ~(1 << y)
#define reversebit(x,y) x ^= (1 << y )
对齐操作
一般对于存储内存地址的变量,需要做内存对齐操作,对齐数量通常都是 2 的倍数,比如 2/4/8/16 位对齐,相对应的二级制是 10(BIN),100(BIN),1000(BIN),10000(BIN);所以对齐的方式是对最后几位二进制位直接置 0 实现是向后对齐,向前对齐是在 value 上加上 base -1 的值
使用宏定义的实现方法如下:
// align back remove tail
#define tAlign(value, base) value & ~(base - 1)
// align front add forward
#define sAlign(value, base) ((value) + (base - 1))/(base) * base
// align front add forward
#define mAlign(value, base) ((value)+ (base - 1) & (~(base - 1)))
取出特定的位
对于一个 int 类型 4字节的整型数,按照 8bit 的方式获取高低位的方法如下:
uint32_t temp = 0x12345678;
printf("test get bits demo \n");
printf("31 ~ 24bits %x \n", (temp & (0xff << 24)) >> 24);
printf("24 ~ 16bits %x \n", (temp & (0xff << 16)) >> 16);
printf("16 ~ 8bits %x \n", (temp & (0xff << 8)) >> 8);
printf("8 ~ 0bits %x \n", (temp & (0xff << 0)) >> 0);
也可以使用下面的宏:
#define BIT_M_TO_N(x, m, n) ((unsigned int)(x << (31-(n))) >> ((31 - (n)) + (m)))
//BIT_M_TO_N(x, 0, 7) ((unsigned int)(x << (31 - (7))) >> ((31 - (7)) + (0)))
//BIT_M_TO_N(x, 0, 7) ((unsigned int)(x << 24) >> ((24) + (0)))
先左移特定的位数,低位补0,默认是无符号类型,所以再进行逻辑右移,将低位的值丢弃,这个宏有一般性,可以获取任意的 [m,n] m ~n 连续 的数值:
printf("%x \n", BIT_M_TO_N(0x12345678, 0, 7));
printf("%x \n", BIT_M_TO_N(0x12345678, 8, 15));
printf("%x \n", BIT_M_TO_N(0x12345678, 16, 23));
printf("%x \n", BIT_M_TO_N(0x12345678, 24, 31));
对特定的字节清零
#define CLEAR_LOW_BYTE0(x) (x &= 0xffffff00) /* 清零第0个字节 */
#define CLEAR_LOW_BYTE1(x) (x &= 0xffff00ff) /* 清零第1个字节 */
#define CLEAR_LOW_BYTE2(x) (x &= 0xff00ffff) /* 清零第2个字节 */
#define CLEAR_LOW_BYTE3(x) (x &= 0x00ffffff) /* 清零第3个字节 */
#define SET_LOW_BYTE0(x) (x |= 0x000000ff) /* 第0个字节置1 */
#define SET_LOW_BYTE1(x) (x |= 0x0000ff00) /* 第1个字节置1 */
#define SET_LOW_BYTE2(x) (x |= 0x00ff0000) /* 第2个字节置1 */
#define SET_LOW_BYTE3(x) (x |= 0xff000000) /* 第3个字节置1 */
2.常用的宏的使用方法
使用 # 将标志符转换为字符串
// 标记前使用“#”特殊符号将其转换为字符串的标记
#define TOSTR(n) #n
printf("tostring %s \n", TOSTR(hello));
int var_a = 100;
printf("%s = %d \n", TOSTR(var_a), var_a);
使用##将两个标志符以字符串的方式连接
//## 用于将两个标志符用字符串的方式连接
#define CONNECT(a, b) a##b
const char *pstr = "Follow your heart";
printf("%s = %s\n", TOSTR(ptr), pstr);
printf("connect a b %d \n", CONNECT(var, _a));
const char *p = "hello world";
CONNECT(debug, Printf)("%s \n", p); // using connect as function name
可变参数宏的定义
使用 ##__VA_ARGS__ 表示是传入的可变参数,跟前面的 字符串类型的 fmt 配合,将可变参数传递到另一个支持可变参数的函数上
#define DBGPRINT(fmt, ...) printf("DEBUG:[%s] line:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__);
DBGPRINT("demo printf %s var_a = %d\n", p, var_a);