有意思的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 ...
随机推荐
- MySQL学习笔记(3)
约束 作用:保证数据的完整性,唯一性 根据字段:分为表级约束(针对2个或者2个以上字段使用),列级约束(针对1个字段使用) 约束类型:NOT NULL 非空约束 PRIMARY KEY 主键约束 U ...
- apache-tomcat-7 设置最大上传.war文件大小[zhuan]
在利用tomcat自带的主机管理页面进行WAR包部署的时候,提示文件太大,无法上传. 解决方案: 找到 /usr/local/apache-tomcat7/webapps/manager/WEB- ...
- HDU-Billboard-2795(线段树)
hdu2795 Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Spark源码学习3
转自:http://www.cnblogs.com/hseagle/p/3673132.html 一.概要 本篇主要阐述在TaskRunner中执行的task其业务逻辑是如何被调用到的,另外试图讲清楚 ...
- Windows主机和Linux虚拟机之间传输文件
如果使用VirtualBox的增强功能, 可以实现两者之间文件相互拖拽. 但某些情况下, 比如增强功能安装遇到难以解决的问题, 或者Linux版本为server版本(例如Ubuntu Server发行 ...
- 在输出视图中使用使用html注释会导致在Chrome中css失效
在做SportsStore例子时,在视图List.cshtml中使用了html注释,即 <!-- 注释 --> 结果在加载css时,chrome浏览器中所有css效果都失效.IE不受影响. ...
- 转: angular编码风格指南
After reading Google's AngularJS guidelines, I felt they were a little too incomplete and also guide ...
- Android 5.x新特性之elevation(阴影),tinting(着色)以及clipping(剪裁)
快过年了,公司也没事做了, 自己也闲了下来,一天天呆着真没意思,闲来没事自己研究研究了Google I/O 2014 发布 Material Design设计,人性化的风格,丰富的色彩,使人机交互更完 ...
- 《windows程序设计》学习_2.2:初识消息,双键的使用
/* 双键的使用 */ #include <windows.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int WINAPI ...
- iOS 检测更新版本
获取app版本URL 数字是appID,在开发者账号app信息中可以找到 #define APP_URL @"http://itunes.apple.com/cn/lookup?id=116 ...