有意思的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 ...
随机推荐
- redis持久化与可用性
redis对于持久化有快照及aof日志文件两种形式. 快照db文件,长处是二进制,大小比aof日志文件小.但会丢失最后一次成功备份时间到down机时间的数据. aof相比而言文件大小就大了点,但相对快 ...
- 如何在其他类中实现继承自CFormView类的对象
今天项目开发中,我们创建了一个对话框资源,并创建了一个派生自CFormView的类(假设为CMyClassDlg)来管理它. CMyClassDlg.h #pragma once // CMyClas ...
- 自己写的sql server触发器练练--高手请您跳过吧
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo ALTER TRIGGER [insertReplyToic] ON [dbo].[bbsReplyTopic] ...
- English - 英语学习小笔记
1.It is...to do sth:做某事是.... 解析:It 是形式主语,后面一半接形容词做表语,to do sth是不定式短语作真正主语. 2.make do和make doing是两种表达 ...
- [Java]HashMap的两种排序方式
先将 Map 中的 key 和 value 全部取出来封装成 JavaBea 数组,再将这个数组排序,排序完成后,重新写回 Map 中,写回时采用 LinkedHashMap 可以保证迭代的顺序. 下 ...
- ASP.NET MVC 音乐商店 - 目录
这一个系列的内容来自微软的音乐商店 Music Store, 这是项目在 Codeplex 上的地址:http://mvcmusicstore.codeplex.com/. 这个项目使用 ASP.NE ...
- StringBuffer&Runtime demo
public class StringBufferDemo02 { public static void main(String[] args) { StringBuffer ...
- 树莓派高级GPIO库,wiringpi2 for python使用笔记(四)实战DHT11解码
DHT11是一款有已校准数字信号输出的温湿度传感器. 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃. 我买的封装好的模块,上边自带了上拉电阻,直接查到树莓派上即可灰 ...
- codeblock编译Object-C
http://blog.csdn.net/ldl22847/article/details/7482971 http://www.cnblogs.com/qingyuan/p/3524791.html ...
- java中常用的数据加密算法
以下为加密的工具类: import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; im ...