有意思的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 ...
随机推荐
- Xposed学习
刚接触,不是太懂,就昨天root荣耀6就花了一天时间,其实root早就ok,只是因为Xposed框架总是提示红色警告,以为不好用,后来试了几次发现,跟手机也有很大关系,有的不能很好的支持框架,有的模块 ...
- tomcat最大线程数的设置(转)
1.Tomcat的server.xml中连接器设置如下 <Connector port="8080" maxThreads="150" minSpareT ...
- Linux学习之输入输出重定向
转自:http://www.cnblogs.com/chengmo/archive/2010/10/20/1855805.html 多谢分享 在了解重定向之前,我们先来看看linux 的文件描述符. ...
- YII与Ace Admin 的集成
目录 一. 前言... 1 二.为什么要使用YII+ace. 1 三.新建YII模块... 1 四.如何修改模板... 3 五.注意的地方... 4 六.整合的不足之处... 4 一. 前言 yii- ...
- JQuery中serialize() 序列化
更多2014/8/24 来源:jquery学习浏览量:1671 学习标签: serialize 本文导读:在jQuery中,当我们使用ajax时,常常需要拼装input数据以键值对(Key/Value ...
- 第三条:私有化构造器或者枚举类型强化Singleton属性
1.5版本之前,我们通常实现单例模式有两种方式: 两种方法前提都是私有化构造器,然后通过不同的方式获取对象. 第一种:通过公共的静态变量获取 public class Elivs{ // 私有化构造器 ...
- codeforces 242E. XOR on Segment 线段树
题目链接 给n个数, 两种操作, 一种是求区间内的数的和, 一种是将区间内的数异或x. 异或x没有什么思路, 单个异或肯定超时, 区间异或也没有办法做....后来才知道可以按位建线段树, 这样建20棵 ...
- hdu 4292 Food 网络流
题目链接 给你f种食物, 以及每种食物的个数, d种饮料, 以及个数, n个人, 以及每个人可以接受的食物种类和饮料种类. 每个人必须得到一种食物和一种饮料. 问最后得到满足的人的个数. 因为一个人只 ...
- 转: 关于异步promises
迄今为止,可能每个JavaScript开发者和他们的祖母都听说过Promises.如果你没有,那么你即将会.promises的概念是由CommonJS小组的成员在 Promises/A规范 中提出来的 ...
- 【转】android权限列表
访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES ,读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permiss ...