有意思的C宏
在Linux内核、嵌入式代码等传统的C代码里,会有一些难以识别的宏定义。我记得在eCos, UBoot, FFmpeg有一些比较BT的宏定义,很难读懂。对于C++程序员来说,最好将这种难读的宏定义转成inline函数或模板函数。本章对这些较难的重定义进行汇总。
1. ; 在宏定义中指定义类型参数
1: #define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)((fpos).__pos)
2: #define VAR_TO_FPOS(fpos, var) (fpos).__pos = (var)
此句在faac的代码里可以见到,其特殊之处是以类型名作为参数,而且是用宏定义一行赋值语句。像如下的调用:
1: uint64_t ret;
2: FPOS_TO_VAR(fpos, uint64_t, ret);
3:
4: uint64_t ret;
5: ret = (uint64_t) (fpos.__pos);
6:
一般可以对宏定义作换行显示,换行后会更清晰易懂一些:
1: #define FPOS_TO_VAR(fpos, typed, var) \
2: (var) = (typed)((fpos).__pos)
2 . 宏定义取结构偏移
这种用法似乎在uCosII中用到,记不清了。举例来说,我们知道一个struct(类型为T)中有一个变量为v,那么由v的地址来得到T的指针呢?
#define S_OFFSET(T,v) (&((T*)0)->v)1: struct ABC
2: {
3: int a;
4: char b;
5: int c;
6: };
7:
8: int main()
9: {
10: unsigned int offset = (unsigned int) S_OFFSET(ABC, b);
11: return 0;
12: }
主要是分析一下(&((T*)0)->v)是个什么意思,相当于以下几种代码:
- T* p = (T*) 0; // 把0地址强转为一个T*
- void* offset = &p->v; // 由于变量p的地址为0,所以成员变量v的偏移就是其地址
T* p = (T*) 0; // 把0地址强转为一个T*
void* offset = &p->v; // 由于变量p的地址为0,所以成员变量v的偏移就是其地址
得到上述偏移之后怎么用呢?在函数传递的过程中,只需要一个v的指针,就可以反推出其所在的结构的地址。而offset一般不方便指定为一个固定值,因为不同环境下的padding可能不一致,也不方便扩展。
- void* p = ...;
- T* t = (T*) (p - offset);
void* p = ...;
T* t = (T*) (p - offset);
3 . 宏定义中的连接符##
这也是一种比较特殊的用法,在eCos3中经常用到。用于替换一个完整名字(类型名、函数、变量名) 的一部分。以下再种写法等效,请仔细体会:
my_type_t var1;
my_type_t var2;
1: struct my_type_t
2: {
3: int a;
4: char b;
5: };
6:
7: #define MY_TYPE(T, name) \
8: T var##name
9:
10: MY_TYPE(my_type_t, 1);
11: MY_TYPE(my_type_t, 2);
12:
13: int main()
14: {
15: unsigned int offset = (unsigned int) S_OFFSET(my_type_t, b);
16: var1.a = 10;
17: }
4 . 宏定义中的字符串#
1: define MYSTR(value) #value
2: int main()
3: {
4: char* cc = MYSTR(hello);
5: }
相当于
char* cc = "hello";
友情链接:C/C++宏的奇巧淫技
有意思的C宏的更多相关文章
- UDF——在udf当中添加几个有意思的宏
很多人的udf都不是自己写的,直接从网上复制粘贴的,编译的时候经常报错.我编写了下面这段示例代码: 我们使用小软件编译: https://www.cnblogs.com/liusuanyatong/p ...
- Linux Kernel代码艺术——系统调用宏定义
我们习惯在SI(Source Insight)中阅读Linux内核,SI会建立符号表数据库,能非常方便地跳转到变量.宏.函数等的定义处.但在处理系统调用的函数时,却会遇到一些麻烦:我们知道系统调用函数 ...
- Shader预处理宏、内置状态变量、多版本编译等
预定义shader预处理宏: Target platform: SHADER_API_OPENGL - desktop OpenGL SHADER_API_D3D9 - Direct3D SHADER ...
- ytu 1059: 判别该年份是否闰年(水题,宏定义)
1059: 判别该年份是否闰年 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 222 Solved: 139[Submit][Status][Web ...
- (转)offsetof与container_of宏[总结]
1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...
- 宏定义中的##操作符和... and _ _VA_ARGS_ _
1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used i ...
- iOS开发笔记--宏定义的黑魔法 - 宏菜鸟起飞手册
宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在 ...
- _T宏的使用
来源自百度. 他的作用是让你的程序支持Unicode编码, 因为Windows使用两种字符集ANSI和UNICODE, 前者就是通常使用的单字节方式, 但这种方式处理像中文这样的双字节字符不方便, ...
- linux初始化宏__init, __exit
我们在内核中经常遇到初始化函数是这样定义的:static int __init init_func(); ,与普通函数相比,定义中多了__init.那么,__init是什么意思呢?还有与其匹配的__e ...
随机推荐
- ZOJ 3794 Greedy Driver spfa
题意: 给定n个点,m条有向边,邮箱容量. 起点在1,终点在n,開始邮箱满油. 以下m行表示起点终点和这条边的耗油量(就是长度) 再以下给出一个数字m表示有P个加油站,能够免费加满油. 以下一行P个数 ...
- [置顶] android 自定义圆角ImageView以及锯齿的处理
看到很多人开发过程中要使用圆角图片时,解决方法有: 1.重新绘制一张图片 2.通过布局来配置 3.通过重写View来实现 其中1,2在这里就不讲了,重点讲讲方法三的实现. 实现一:通过截取画布一个圆形 ...
- 虚拟键盘,移动web开发的痛
原生APP的弹出虚拟键盘和收回虚拟键盘,输入框始终贴在虚拟键盘的上方.如下图: 如果移动端web也想做类似的功能,可以实现吗? 你可能会说着:“不就是放一个position: fixed;的输入框在 ...
- 浅谈HtmlParser
使用Heritrix抓取到自己所需的网页后,还需要对网页中的内容进行分类等操作,这个时候就需要用到htmlparser,但是使用htmlparser并不是那么容易!因为相关的文档比较少,很多更能需要开 ...
- iOS 导航条的影响
如果是push出来的控制器,self.view的(0,0)点从状态栏下面开始: 如果有present出来的控制器,self.view的(0,0)点包含状态栏:
- 解决 jQuery-datepicker无法弹出日期的问题
1.确保 jquery-ui.css.jquery.min.js和jquery-ui.min.js 三个文件的引用 2.如果是下载网站上的html,需要删除时间<input>的hasDat ...
- java 调用jdbc 实现excel和csv的导入和导出
jdbc 的连接 实体类 package com.gpdi.mdata.web.manage.database.data;public class DBQueryData {private Strin ...
- win8 iis安装及网站发布(转)
系统:win8 环境:vs2012 一:安装IIS 比较win7的安装来说,多选了几个钩钩,不然会报错,偶就遇到这样的错误. 控制面板->程序和功能->启动和关闭windows功能,钩钩图 ...
- R与数据分析旧笔记(六)多元线性分析 上
> x=iris[which(iris$Species=="setosa"),1:4] > plot(x) 首先是简单的肉眼观察数据之间相关性 多元回归相较于一元回归的 ...
- VirtualBox 中ubuntu访问window下共享目录
1,vbox中设置window需要共享给vbox中ubuntu的文件夹,主要要注意共享文件夹名称windowShare. 2,在ubuntu中挂载windowShare. sudo mount -t ...