计算向向上取整的商
由于两数相除,默认是向下取整,而这里是向上取整数
参考
计算向下取整的整数倍数
如:m = 5 n = 3,3的整数倍有3,6,9,12,但是对于5向下取整为3
解决:先用m/n得到商,然后再剩以n
计算向上取整的整数倍数
如:m = 5 n = 3,3的整数倍有3,6,9,12,但是对于5向上取整为6
解决:先用m/n得到商,然后(商+1)再剩以n
当n为2的n次方时,改进上面的算法
其实这是Linux用来对指针做字节对齐的宏
核心点在于a为 ,所有 a - 1 再取反 后低位全为 0 高位全为1
举例:x = 5 a = 4(4 -->> 1111 1100)
由于高位不管是取0还是取1都是都是4的整数倍,如(8:0000 1000 16:0001 0000 24:0001 1000)
注意:a必须是
还有一个宏用于判断是否字节对齐
参考
强制编译出错
注意核心表达式sizeof(char[1 - 2*!!(condition)])的作用,首先对条件表达式进行两次取反,这可以保证进行1 - 2*!!(condition)的结果只有两种值:条件为0时结果为1或者不为0则结果为-1,显然char[-1]将会导致编译器报错。注意:两次取反的目的是为了将表达式的值转换为逻辑值。
- condition != 0:编译器报错
- condition = 0:上面返回1 下面返回0
主要用在结构或其它自定义类型不满足指定大小就需要编译报错。
根据机构体成员地址找到结构体首地址
这个大家应该都很熟悉了,我这里就不说了
如果不懂可以参考我的这篇博客,有详细的解释
各个数据类型的最大值和最小值
va_list 、va_start、 va_arg、 va_end
当我们用可变参数来作为函数参数时,怎么一个一个的取得参数,如下
int DebugPrint(const char *pcFormat, ...) {
}
Glibc中有对应的宏,虽然这不是内核中的宏,但是还是可以拿来讲一下。
typedef char *va_list;
va_start宏,获取可变参数列表的第一个参数的地址(list是类型为va_list的指针,param1是可变参数最左边的参数):
va_arg宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(mode参数描述了当前参数的类型):
va_end宏,清空va_list可变参数列表:
简单用法1
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
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);
}