下面6个声明语句分别声明的是什么?
如果不能快速地分清,我们就来一起来学习一下。首先我们先了解一下标识符,标识符是标识某个实体的一个符号,用于给变量、常量、函数、语句块等命名。上面6个声明语句中有6个标识符:example1,example12 ,example3 ,example4 ,example5 ,example6 。
接下来我们来学习一个原则:小鸭子原则(作者原创)。小鸭子从蛋中孵化出来之后,最先看到的活动物是它们的母亲,母亲走到哪里,它们就跟到哪里。
小鸭子原则就是:标识符最先跟谁结合,它就是什么类型的。我们运用小鸭子原则分析一下上面6条语句:
1、u8 *example1
example1和*结合 ,因此example1是一个指针。
2、u8 *example2[3]
这里耦合符号有和[],[]的优先级高于(如果不清楚运算优先级的朋友们可以看一下我另外一篇文章《C语言运算优先级记忆口诀》),example2先和[]结合 ,因此example2[]是个数组。我们可以将example2[]等效为 数组,分析如下:
u8 example2[3] 理解为 u8 数组 ,说明example2是一个u8类型的数组指针。
3、*u8 (example3)[3]
这里耦合符号有(),和[],优先级顺序为:() > [] > * 。()起到聚组作用(提高优先级),example3先和结合,因此*example3是指针。我们可以将(*example3)等效 ”指针”,分析如下:
u8 (*example3)[3] 理解为 “ u8 指针[3] ”, 说明example3 是一个u8类型的指针数组。
4、u8 *example4()
这里耦合符号有()和*,()的优先级高于* ,example4先和()结合,因此example4()是 函数,我们可以将example4()等效 函数,分析如下:
u8 example4() 理解为*“ u8* 函数”,说明example4 是一个返回类型为u8*的函数**。
5、u8 (*example5)()
这里耦合符号有(),和(),example5先和结合,因此example5是指针,我们可以将example5等效为* 指针,分析如下:
u8 (*example5)() 理解为 u8 指针() ,说明example5是一个返回类型u8函数指针。
可能关于u8 指针();有些朋友难以理解。我们来分解一下:
u8 a; u8 *a;
a是u8 类型变量,*a是u8 类型指针
typedef struct dog
{
char name[20];
}dog_t;
dog_t my_dog; dog_t *my_dog;
my_dog是一个dog_t类型结构体,*my_dog是一个dog_t类型结构体指针
我们可以认为 nnn 是一个x类型变量,*nnn是一个x类型变量指针。
根据这个原则:u8 example5() 是个函数 , u8 (*example5)()是个函数指针。
6、u8 (*example6[3])()
这里耦合符号有(),*和[],example6先和[]结合,因此example6[]是一个数组,我们可以将example6[]等效为“数组”:
u8 (*example6[3])() 理解为 u8( * 数组)(),这是一个函数指针,说明example6是一个函数指针数组。
经过上面的学习我们可能已经学会了区分指针,数组,函数的混合体,再来看一个复杂例子:
void (*signal (int signo,void (*func)(int) ) ) (int) ;
经过上面朋友们可以一步一步使用小鸭子原则进行分析,如果不清楚就百度搜索“signal函数”,这是linux中的信号函数。
下面我们深入研究一下指针在计算机中是怎么工作的。
talk is cheap, show me the code! 我们一起来看如下代码:
反汇编代码如下:
data1和data_p 这两个变量在RAM中的位置为:0x1fff8009(data1) ,0x1fff800c(*data_p)
我们再一起看看data1和 data_p 这两个变量在RAM中值(程序运行完之后的值)
data_p 这个指针变量存放着data1的RAM地址0X1FFF8009 (09 80 FF 1F 为小端模式)
创作不易希望喜欢的朋友们点赞,转发,关注。
作者:李巍
Github:liyinuoman2017