电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
【粉丝问答25】函数指针定义的一个错误
分 享
扫描二维码分享
【粉丝问答25】函数指针定义的一个错误
C语言
一口Linux
关注
发布时间: 2021-06-16
丨
阅读: 989
## 1. 问题 某个函数指针的使用:编译时出错了。 type defaults to 'int' in declaration of 'on_touch_messgae_handle'[-Wimplicit-int] typedef(*on_touch_messgae_handle)(touch_message_t); ![问题 ](https://img-blog.csdnimg.cn/20210411182905424.jpg)粉丝源码如下: ![源码](https://img-blog.csdnimg.cn/20210411182917366.jpg) ## 2. 分析 ### 1) 结构解析 ```c 1 struct touch_message 2 { 3 rt_uint16_t x; 4 rt_uint16_t y; 5 rt_uint8_t event; 6 }; 7 typedef struct touch_message * touch_message_t; 8 typedef (*on_touch_messgae_handle)(touch_message_t); ``` 首先看下7行这个类型定义: ```c typedef struct touch_message * touch_message_t; ``` 定义后 ```c touch_message_t ``` 等价于 ```c struct touch_message * ``` 就是说我们如果用touch_message_t 定义的变量是一个struct touch_message类型的一个指针。 再来分析下8行这个定义: ```c typedef (*on_touch_messgae_handle)(touch_message_t); ``` 可以替换成下面这个定义 ```c typedef (*on_touch_messgae_handle)(struct touch_message *); ``` ### 2) 分步解析 有的C语言基础不是很好的朋友,可能无法一眼看出来这个定义, 为了让新手更容易看懂,我们来看一下下面一个递进式的定义: ```c int fun; ``` 这是一个整型变量fun; ```c int fun(); ``` 这是一个函数fun, 参数 : 空 返回值: int型 ```c int fun(struct touch_message *); ``` 这是一个函数fun, 参数 : struct touch_message *的一个指针 返回值: int型 上述的变化都好理解,下面我们将fun做如下修改: ```c int (*fun)(struct touch_message *); ``` 括号的优先级最高,(*fun)一旦如此定义,那么fun就要先和*结合, 所以fun变成了一个指针, 那么该指针指向什么呢? 就需要看外面是如何定义的, 右边是(struct touch_message * ),左边是int, 所以说明指针指向的是一个函数, 参数 : struct touch_message *的一个指针 返回值: int型 >举例: >将函数my_fun赋值给函数指针fun。 int my_fun(struct touch_message *) { } int (*fun)(struct touch_message *); fun = my_fun; 这里有一个隐藏的知识点,函数名其实也是一个地址,而且赋值的时候函数类型必须和函数指针类型一致。 ```c typedef int (*fun)(struct touch_message *); ``` 如果左边再加上typedef呢? 相当于是设置fun为新的类型,我们可以用fun来定义一个函数指针, 该函数类型同上。 >举例 >用新的类型定义一个函数指针变量,并给他赋值。 >typedef int (*fun)(struct touch_message *); >int my_fun(struct touch_message *) { } >fun fun_ptr; >fun_ptr = my_fun; 然后将参数修改为,touch_message_t,就得到了粉丝的源码中的样子, ```c typedef int (*fun)(touch_message_t); ``` 但是粉丝的源码中定义的函数类型缺少了对函数返回值的描述,所以左侧增加一个int或者其他类型即可即可。 ## 3. 函数指针 函数指针在linux内核中使用非常频繁, 比如字符设备,内核给多有的字符设备提供了一个统一的接口,我们对设备的所有操作被抽象成read、write、open、close等,并封装到结构体struct file_operations 中: ```c struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); int (*show_fdinfo)(struct seq_file *m, struct file *f); }; ``` 那么我们应该如何定义该结构体变量并初始化呢? ```c static struct file_operations hello_ops = { .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, }; ``` 函数定义如下: ```c static int hello_open (struct inode *inode, struct file *filep) { return 0; } static int hello_release (struct inode *inode, struct file *filep) { return 0; } static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos) { return size; } static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos) { return size; } ``` 注意,函数的参数和返回值,必须严格按照结构体struct file_operations中的类型定义。
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
一口Linux
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交