1.在linux 2.6.38内核的driver/input/keyboard目录下的gpio_keys.c源码中的486行开始如下
ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。例如:
在实际的程序设计中,为迎合ANSI标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码:
7. 指向多维数组的指针定义与分配
a. 二维数组的定义
b. 三维数组的定义与分配
8. 联合体大小
- for (i = 0; i < pdata->nbuttons; i++) {
- struct gpio_keys_button *button = &pdata->buttons[i];
- struct gpio_button_data *bdata = &ddata->data[i];
- unsigned int type = button->type ?: EV_KEY;
- bdata->input = input;
- bdata->button = button;
- error = gpio_keys_setup_key(pdev, bdata, button);
- if (error)
- goto fail2;
- if (button->wakeup)
- wakeup = 1;
- input_set_capability(input, type, button->code);
- }
其中红色一行出现的用法解释:
首先,三目运算符的用法如下,如果j大于0,那么i = j,否则i = k。
- i = j ?: k;
其次,"->"与"."运算符的区别。
"->" 用于表示指向对象的指针的成员;
"." 用于表示一般成员的成员。
<对象指针名> -> <成员名> 和 (*<对象指针名>) . <成员名> 等价。
2.static限定词
c语言中static的语义
1.static变量:
1).局部
a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。
b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
1).局部
a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。
b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
当static用来修饰局部变量的时候,它就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区。但是局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问。
2).全局
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
2.static函数(也叫内部函数)
只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
2.static函数(也叫内部函数)
只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)
使用静态函数的好处:
静态函数会被自动分配在一个一直使用的存储区,直到退出应用程序实例,
避免了调用函数时压栈出栈,速度快很多。
关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
3.空指针和未初始化的指针
空指针在概念上不同于未初始化的指针。空指针可以确保不指向任何对象或函数; 而未初始化指针则可能指向任何地方。
按照ANSI(American National Standards Institute)标准,
不能对void指针进行算法操作,即下列操作都是不合法的:
- void * pvoid;
- pvoid++; //ANSI:错误
- pvoid += 1; //ANSI:错误
- int *pint;
- pint++; //ANSI:正确 pint++的结果是使其增大sizeof(int)
但是大名鼎鼎的
GNU(GNU's Not Unix的缩写)则不这么认定,它
指定void *的算法操作与char *一致。因此下列语句在GNU编译器中皆正确:
- pvoid++; //GNU:正确
- pvoid += 1; //GNU:正确 pvoid++的执行结果是其增大了1
- //内核代码示例(linux3.2.8/driver/video/s3c-fb.c 其probe函数里有如下代码):
- /* initialise colour key controls */
- for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
- void __iomem *regs = sfb->regs + sfb->variant.keycon;
- //GNU下空指针可以算数运算,并且算法操作与char *一致。
- //因此,如下代码,可以加,并且加的是(win * 8)的值,而非((win * 8) * 4)
- regs += (win * 8);
- writel(0xffffff, regs + WKEYCON0);
- writel(0xffffff, regs + WKEYCON1);
- }
- void * pvoid;
- (char *)pvoid++; //ANSI:正确;GNU:正确
- (char *)pvoid += 1; //ANSI:错误;GNU:正确
GNU和ANSI还有一些区别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。但是我们在真实设计时,还是应该尽可能地迎合ANSI标准。
4. 常量指针与指针常量
a.
常量指针:“const int *p; ” 与 “int const *p;” 等价。
常量指针
不能靠解引用改变它所指向的对象的值,以此保护它所指向的常量的常量值。但是,它本身的指针值可以改变。
b.
指针常量:“int *const p = &n;"
指针常量
可以靠解引用改变它所指向的对象的值,但是它本身的值不能改变,且必须在声明时初始化。
- int const *p; //常量指针
- p = &n; //指针常量不可这么用
- int *const p; //指针常量
- *p = n; //常量指针不可这么用
5. '##'宏参数贴合
- /*
- * Set of macros to define architecture features. This is built into
- * a table by the linker.
- */
- #define MACHINE_START(_type,_name) \
- static const struct machine_desc __mach_desc_##_type \
- __used \
- __attribute__((__section__(".arch.info.init"))) = { \
- .nr = MACH_TYPE_##_type, \
- .name= _name,
- #define MACHINE_END \
- };
如上代码时宏定义MACHINE_START,其中的'##'告诉编译器把宏参数_type和MACH_TYPE贴合。
- //mach-jason6410.c中
- MACHINE_START(JASON6410, "JASON6410")
- /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
- .atag_offset = 0x100,
- .init_irq = s3c6410_init_irq,
- .map_io = jason6410_map_io,
- .init_machine = jason6410_machine_init,
- .timer = &s3c24xx_timer,
- MACHINE_END
- //展开后
- static const struct machine_desc __machine_desc_JASON6410
- __used
- __atrribute__((__section__(".arch.info.init"))) = {
- .nr= MACH_TYPE_JASON6410,
- .name= "JASON6410",
- /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
- .atag_offset = 0x100,
- .init_irq = s3c6410_init_irq,
- .map_io = jason6410_map_io,
- .init_machine = jason6410_machine_init,
- .timer = &s3c24xx_timer,
- };
6. 指向结构体的指针
如下代码中,win + 1,指针偏移的是一个结构体大小的位置。在framebuffer_alloc中,分配了fb_info结构体,并为s3c_fb_win结构体和调色板缓冲区分配了内存。win指向s3c_fb_win结构体,加1后指向调色板缓冲区起始地址。然后强制转换为palette_buffer类型的指针,并赋值给win中的palette_buffer成员。
- 摘自linux3.2.8/driver/video/s3c-fb.c的s3c_fb_probe_win中的代码
- struct s3c_fb_win *win;
- int palette_size;
- fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
- palette_size * sizeof(u32), sfb->dev);
- //指向驱动私有数据中的s3c_fb_win结构体,也是上面函数额外分配的内存的起始地址
- win = fbinfo->par;
- win->palette_buffer = (u32 *)(win + 1);
7. 指向多维数组的指针定义与分配
a. 二维数组的定义
- int a[m][n];
- int (*p)[n];
- p=a;
- int a[l][m][n];
- int (*p)[m][n];
- p = (int (*)[m][n])malloc(l*m*n*sizeof(int));
8. 联合体大小
- union u_tag {
- char cVals[16];
- int nVal;
- double dVal;
- }u;
- sizeof(u); // 等于枚举元素中最长成员值,这里为16。注意:不同于数组中的情况,如果是数组,则为28。