struct var_data
{
int len;
char data[0];
}
struct var_data s;
for (i = 0; i < s.len; i++)
printf("%02x \n", s.data[i]);
==================================================================================
switch (ch)
{
case '0'... '9': c -= '0';
break;
case 'a'... 'f': c -= 'a' - 10; //A 65 a 97 '' 32
break;
case 'A'... 'F': c -= 'A' - 10;
break;
}
==================================================================================
#define min_t(type,x,y) \
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
int ia, ib, mini;
float fa, fb, minf;
mini = min_t(int, ia, ib);
minf = min_t(float, fa, fb);
下面一个更好的
==================================================================================
typeof(x)语句可以获得x 的类型,因此,我们可以借助typeof 重新定义min 这个宏:
#define min(x,y) ({ \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; }) // 为啥加大括号? 因为里面是一段代码。
首先,我们此处想要实现的目的是,在计算两个数的最小值之前,希望去判断一下两个值的类型是否一致,而由于C语言本身不支持我们去做类似于这样的操作typeof(_x)==typeof(_y),所以在此,通过故意判断他们2个的地址指针是否相等,而显然&_x,即x的地址,是不可能等于&_y的,但是这句话(void) (&_x == &_y);使得,如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,则会引起编译器产生一个编译警告,提示你这两个值的类型不同。
(void) (&_x == &_y); 用于判断输入的两个值的类型是否是一致的。如果不一致,那么编译器就会做出如下警告:warning: comparison of distinct pointer types lacks a cast
(void) (&_x == &_y); 中的void,表示将表达式(&_x == &_y); 所得到的结果(此处肯定是逻辑上的假,值为0)忽略掉。如果不加void,则会提示你这行代码是无意义的,没人用到。
因为,如果如此定义,那么对于一些特殊的值传入此宏之后,就会产生一些副作用,产生的结果,就不是我们想要的了,比如:
min(++a,++b) ==> ((++a)<(++b))?(++a) : (++b)
就使得,a++和b++分别执行了2次,而且min的结果,也不对了。而用上面那个复杂的定义,多加了局部变量_x和_y,就可以避免此类问题了
==================================================================================
int printf( const char *format [, argument]... );
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
而在GNU C 中,宏也可以接受可变数目的参数,例如:
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
这里arg 表示其余的参数可以是零个或多个,这些参数以及参数之间的逗号构成 arg 的值,在宏扩展时替换 arg,例如下列代码:
pr_debug("%s:%d",filename,line)
会被扩展为:
printk("%s:%d", filename, line)
使用“##”的原因是处理arg 不代表任何参数的情况,这时候,前面的逗号就变得多余了。使用“##”之后,GNU C 预处理器会丢弃前面的逗号,这样,代码:
pr_debug("success!\n")
会被正确地扩展为:
printk("success!\n") // 没有逗号
而不是:
printk("success!\n",) //多了一个逗号
#define A1(name, type) type name_##type##_type 或
#define A2(name, type) type name##_##type##_type
A1(a1, int); /* 等价于: int name_int_type; */
A2(a1, int); /* 等价于: int a1_int_type; */
至于单独一个#,则表示 对这个变量替换后,再加双引号引起来。比如
#define __stringify_1(x) #x
那么
__stringify_1(linux) <==> ”linux”
==================================================================================
static char *book_name = "深入浅出Linux 设备驱动";
static int num = 4000;
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);
参数类型可以是 byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool 或invbool(布尔的反),
在模块被编译时会将module_param 中声明的类型与变量定义的类型进行比较,判断是否一致。
insmod hello.ko num=20
则可以 cat /sys/module/hello/parameters/num ,看到为 20
1.定义模块参数的方法:
module_param(name, type, perm);
其中,name:表示参数的名字;
type:表示参数的类型;
perm:表示参数的访问权限;
2. 数组类型模块参数的定义:
用逗号间隔的列表提供的值;
声明一个数组参数:
module_param_array(name, type, num, perm);
其中,name:表示数组的名字;
type:表示参数的类型;
num :表示数组中元素数量;
perm:表示参数的访问权限;
3.type支持的基本类型有:
bool :布尔类型
invbool:颠倒了值的bool类型;
charp :字符指针类型,内存为用户提供的字符串分配;
int :整型
long :长整型
short :短整型
uint :无符号整型
ulong :无符号长整型
ushort :无符号短整型
static char *book_name = "dissecting Linux Device Driver";
static int num = 4000;
static int book_init(void)
{
printk(KERN_INFO " book name:%s\n",book_name);
printk(KERN_INFO " book num:%d\n",num);
return 0;
}
static void book_exit(void)
{
printk(KERN_ALERT " Book module exit\n ");
}
module_init(book_init);
module_exit(book_exit);
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);
==================================================================================
Linux 2.6 的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址。
模块可以使用如下宏导出符号到内核符号表:
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名); 。EXPORT_SYMBOL_GPL()只适用于包含 GPL 许可权的模块
cat /proc/kallsyms | grep integar
=======================&#
实用C---- 记录总结 tool
最新推荐文章于 2022-05-09 15:01:06 发布
本文主要介绍了C语言的一些实用工具和编程技巧,包括编译器使用、调试方法、代码优化以及常见问题的解决策略,旨在帮助开发者提高C语言编程效率和代码质量。
摘要由CSDN通过智能技术生成