在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)是个什么意思,相当于以下几种代码:

  1. T* p = (T*) 0;  // 把0地址强转为一个T*  
  2. void* offset = &p->v; // 由于变量p的地址为0,所以成员变量v的偏移就是其地址 
T* p = (T*) 0;  // 把0地址强转为一个T*
void* offset = &p->v; // 由于变量p的地址为0,所以成员变量v的偏移就是其地址

得到上述偏移之后怎么用呢?在函数传递的过程中,只需要一个v的指针,就可以反推出其所在的结构的地址而offset一般不方便指定为一个固定值,因为不同环境下的padding可能不一致,也不方便扩展。

  1. void* p = ...;  
  2. 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宏的更多相关文章

  1. UDF——在udf当中添加几个有意思的宏

    很多人的udf都不是自己写的,直接从网上复制粘贴的,编译的时候经常报错.我编写了下面这段示例代码: 我们使用小软件编译: https://www.cnblogs.com/liusuanyatong/p ...

  2. Linux Kernel代码艺术——系统调用宏定义

    我们习惯在SI(Source Insight)中阅读Linux内核,SI会建立符号表数据库,能非常方便地跳转到变量.宏.函数等的定义处.但在处理系统调用的函数时,却会遇到一些麻烦:我们知道系统调用函数 ...

  3. Shader预处理宏、内置状态变量、多版本编译等

    预定义shader预处理宏: Target platform: SHADER_API_OPENGL - desktop OpenGL SHADER_API_D3D9 - Direct3D SHADER ...

  4. ytu 1059: 判别该年份是否闰年(水题,宏定义)

    1059: 判别该年份是否闰年 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 222  Solved: 139[Submit][Status][Web ...

  5. (转)offsetof与container_of宏[总结]

    1.前言 今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大.offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址 ...

  6. 宏定义中的##操作符和... and _ _VA_ARGS_ _

    1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used i ...

  7. iOS开发笔记--宏定义的黑魔法 - 宏菜鸟起飞手册

    宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在 ...

  8. _T宏的使用

    来源自百度.   他的作用是让你的程序支持Unicode编码, 因为Windows使用两种字符集ANSI和UNICODE, 前者就是通常使用的单字节方式, 但这种方式处理像中文这样的双字节字符不方便, ...

  9. linux初始化宏__init, __exit

    我们在内核中经常遇到初始化函数是这样定义的:static int __init init_func(); ,与普通函数相比,定义中多了__init.那么,__init是什么意思呢?还有与其匹配的__e ...

随机推荐

  1. C++_前置声明

    为什么要有前置声明? eg: -定义一个类 class A,这个类里面使用了类B的对象b,然后定义了一个类B,里面也包含了一个类A的对象a,就成了这样: //a.h #include "b. ...

  2. C++_知识点_结构体/枚举/联合

    //C++中结构体的不同之处 #include <iostream> #include <string> using namespace std; int main(void) ...

  3. IIS发布网站:CS0016: 未能写入输出文件的解决方法

    “/”应用程序中的服务器错误.-------------------------------------------------------------------------------- 编译错误 ...

  4. poj 1321 棋盘问题 递归运算

    棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19935   Accepted: 9933 Description ...

  5. Android 汉字转拼音之JNI篇

    package com.tool.hz2py; import android.os.Bundle; import android.app.Activity; import android.view.M ...

  6. poj 1091 跳骚

    /** 题意: 求对于小于m的n个数, 求x1*a1 + x2*a2+x3*a3........+xn*an = 1 即求 a1,a2,a3,....an 的最大公约数为1 , a1,a2....an ...

  7. ExtJS 修改load paging时的参数

    ExtJS 的pagingToolbar 在翻页的时候传入的参数是固定的  分别是start 和 limit(其中limit的值就是store.pageSize的值) 如何在每次翻页的时候传入自己的参 ...

  8. 在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be closed first”

    在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be ...

  9. Qt qss一些伪装态,以及margin与padding区别

    伪状态    描述 :checked    button部件被选中:disabled    部件被禁用:enabled    部件被启用:focus    部件获得焦点:hover    鼠标位于部件 ...

  10. cocos2dx CCTextFieldTTF

    CCTextFieldTTF是一个提供文本输入的控件. 先上个简单的例子 CCSize size = __winSize; CCTextFieldTTF* textEdit = CCTextField ...