-
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。