Linux常用内核宏

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40732350/article/details/98742497

计算向向上取整的

由于两数相除,默认是向下取整,而这里是向上取整数

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))

参考:https://www.cnblogs.com/cmembd/p/3493597.html

计算向下取整的整数倍数

如:m = 5  n = 3,3的整数倍有3,6,9,12,但是对于5向下取整为3

解决:先用m/n得到商,然后再剩以n

#define DOWN_INT(M, N) (((M) / (N)) * (N))

计算向上取整的整数倍数

如:m = 5  n = 3,3的整数倍有3,6,9,12,但是对于5向上取整为6

解决:先用m/n得到商,然后(商+1)再剩以n

#define UP_INT(M, N) ((((M) + ((N) - 1)) / (N)) * (N))

当n为2的n次方时,改进上面的算法

其实这是Linux用来对指针做字节对齐的宏

#define ALIGN(x, a)           __ALIGN_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_MASK(x, mask) ( ((x) + (mask)) & ~(mask) )
#define PTR_ALIGN(p, a)       ((typeof(p))ALIGN((unsigned long)(p), (a)))

核心点在于a为  2^{N},所有  a - 1 再取反 后低位全为  0  高位全为1

举例:x = 5  a = 4(4   -->>    1111 1100)

由于高位不管是取0还是取1都是都是4的整数倍,如(8:0000 1000    16:0001 0000    24:0001 1000)

注意:a必须是 2^{N}

还有一个宏用于判断是否字节对齐

#define IS_ALIGNED(x, a)      ( ( (x) & ((typeof(x))(a) - 1) ) == 0)

参考:https://www.cnblogs.com/3me-linux/p/6026914.html

强制编译出错

#define BUILD_BUG_ON(e)         (sizeof(char[1 - 2 * !!(e)])    )
#define BUILD_BUG_ON_ZERO(e)    (sizeof(char[1 - 2 * !!(e)]) - 1)

 

注意核心表达式sizeof(char[1 - 2*!!(condition)])的作用,首先对条件表达式进行两次取反,这可以保证进行1 - 2*!!(condition)的结果只有两种值:条件为0时结果为1或者不为0则结果为-1,显然char[-1]将会导致编译器报错。注意:两次取反的目的是为了将表达式的值转换为逻辑值。

  • condition != 0:编译器报错
  • condition =  0:上面返回1   下面返回0

主要用在结构或其它自定义类型不满足指定大小就需要编译报错。

根据机构体成员地址找到结构体首地址

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({			\
	const typeof(((type *)0)->member) * __mptr = (ptr);	\
	(type *)((char *)__mptr - offsetof(type, member)); })

这个大家应该都很熟悉了,我这里就不说了

如果不懂可以参考我的这篇博客,有详细的解释:https://blog.csdn.net/qq_40732350/article/details/82960082

 

各个数据类型的最大值和最小值

#define USHRT_MAX	((u16)(~0U))
#define SHRT_MAX	((s16)(USHRT_MAX>>1))
#define SHRT_MIN	((s16)(-SHRT_MAX - 1))
#define INT_MAX		((int)(~0U>>1))
#define INT_MIN		(-INT_MAX - 1)
#define UINT_MAX	(~0U)
#define LONG_MAX	((long)(~0UL>>1))
#define LONG_MIN	(-LONG_MAX - 1)
#define ULONG_MAX	(~0UL)
#define LLONG_MAX	((long long)(~0ULL>>1))
#define LLONG_MIN	(-LLONG_MAX - 1)
#define ULLONG_MAX	(~0ULL)

va_list 、va_start、 va_arg、 va_end

当我们用可变参数来作为函数参数时,怎么一个一个的取得参数,如下

int DebugPrint(const char *pcFormat, ...) {

}

Glibc中有对应的宏,虽然这不是内核中的宏,但是还是可以拿来讲一下。

typedef char *va_list;

va_start宏,获取可变参数列表的第一个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数):
#define va_start(list,param1)   ( list = (va_list)&param1+ sizeof(param1) )

va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(mode参数描述了当前参数的类型):
#define va_arg(list,mode)   ( (mode *) ( list += sizeof(mode) ) )[-1]

va_end宏,清空va_list可变参数列表:
#define va_end(list) ( list = (va_list)0 )

简单用法1

#include <stdio.h>
#include <stdarg.h>
void var_test(char *format, ...) {
    va_list list;
    va_start(list,format);   
    char *ch;
    while(1) {
         ch = va_arg(list, char *); //ch获得当前参数的地址,调用后,list指向下一个参数
         if(strcmp(ch,"") == 0) {    
               printf("\n");
               break;
         }
         printf("%s ",ch);
     }
     va_end(list);
}
int main() {
    var_test("test","this","is","a","test","");
    return 0;
}

简单用法2

#include<stdarg.h>
#include<stdio.h>
int sum(int num_args, ...) {
   int val = 0;
   va_list ap;
   int i;
   va_start(ap, num_args);
   for(i = 0; i < num_args; i++) {
      val += va_arg(ap, int);
   }
   va_end(ap);
   return val;
}
int main(void) {
   printf("10、20 和 30 的和 = %d\n",  sum(3, 10, 20, 30) );
   return 0;
}

简单用法3

int DebugPrint(const char *pcFormat, ...) {
	va_list tArg;
	/* 可变参数的处理, 抄自glibc的printf函数 */
	va_start (tArg, pcFormat);
	iNum = vsprintf (strTmpBuf, pcFormat, tArg);
	va_end (tArg);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页