目录

1 概述

2 常见的预处理指令

3 其他预编译指令

4 预定义标识符

5 #define

5.1 使用宏函数,定义类的成员函数

5.2 Eigen中使用宏函数,重写类的成员函数(内存分配方式)


1 概述

预处理指令提供按条件跳过源文件中的节、报告错误和警告条件,以及描绘源代码的不同区域的能力。比如 使用术语“预处理指令”为了与 C 和 C++ 编程语言保持一致。

  预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。
  文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。
  条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。
  布局控制:#progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。
  宏替换:#define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。

2 常见的预处理指令

  ● #define 宏定义
  ● #undef 未定义宏
  ● #include 文本包含
  ● #ifdef 如果宏被定义就进行编译
  ● #ifndef 如果宏未被定义就进行编译
  ● #endif 结束编译块的控制
  ● #if 表达式非零就对代码进行编译
  ● #else 作为其他预处理的剩余选项进行编译
  ● #elif 这是一种#else和#if的组合选项
  ● #line 改变当前的行数和文件名称
  ● #error 输出一个错误信息

  ● #pragma 为编译程序提供非常规的控制流信息

3 其他预编译指令

除了上面我们说的集中常用的编译指令,还有3种不太常见的编译指令:#line、#error、#pragma,我们接下来就简单的谈一下。
  #line的语法如下:

  例如:#line 30 a.h 其中,文件名a.h可以省略不写。
  这条指令可以改变当前的行号和文件名,例如上面的这条预处理指令就可以改变当前的行号为30,文件名是a.h。初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,我们知道编译器对C++源码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。

  例如:

  这条指令主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。

4 预定义标识符

为了处理一些有用的信息,预处理定义了一些预处理标识符,虽然各种编译器的预处理标识符不尽相同,但是他们都会处理下面的4种:
  1、__FILE__ 正在编译的文件的名字
  2、__LINE__ 正在编译的文件的行号
  3、__DATE__ 编译时刻的日期字符串,例如: "25 Dec 2000"
  4、__TIME__ 编译时刻的时间字符串,例如: "12:30:55"
  例如:cout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;

5 #define

#define M 5     //无参宏, 代码中所有使用M的地方在编译时会被替换成5#define COUNT(M) M * M               //有参宏, M最好加上括号
//使用:printf("COUNT = %d\n", COUNT(10));   // 替换为: COUNT(10) = 10 * 10// 输出结果: COUNT = 100

宏名中不能有空格,宏名与形参表之间也不能有空格,而形参表中形参之间可以出现空格

#define SUM (a,b) a + b              //定义有参宏
// printf("SUM = %d\n", SUM(1,2));      //调用有参宏。Build Failed!
// 因为 SUM 被替换为:(a,b) a + b//正确写法:
#define SUM(a,b) (a) + (b)

5.1 使用宏函数,定义类的成员函数

#define EIGEN_MAX_ALIGN_BYTES 1
#if EIGEN_MAX_ALIGN_BYTES!=0 //当条件满足就定义两个函数#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \void functionA1(int num) { \std::cout << "==> call functionA1:" << NeedsToAlign << std::endl; \} \void functionA2(int num)  { \std::cout << "==> call functionA2:" << num << std::endl; \}
#else                       //当条件不满足,就定义一个空(什么也不定义)#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
#endifclass EigenTest{
public:enum { NeedsToAlign = 230 };EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign);
};
int main(int argc, char* argv[])
{EigenTest et;et.functionA1(100); // 当 EIGEN_MAX_ALIGN_BYTES等于0时,et就没有functionA1、functionA2两个成员函数的定义return 0;
}

5.2 Eigen中使用宏函数,重写(override)类的成员函数(内存分配函数)

先来些宏定义,对分配内存new delete的函数进行重新定义。这里的NeedsToAlign作为宏函数的参数,传入到函数体中作为一个模板参数(或者普通形参)使用。若EIGEN_MAX_ALIGN_BYTES=0, 就定义一个空的宏(啥也不做,宏替换的地方什么也没有)

/*****************************************************************************
*** Implementation of EIGEN_MAKE_ALIGNED_OPERATOR_NEW [_IF]                ***
*****************************************************************************/#if EIGEN_MAX_ALIGN_BYTES!=0#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \void* operator new(std::size_t size, const std::nothrow_t&) EIGEN_NO_THROW { \EIGEN_TRY { return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); } \EIGEN_CATCH (...) { return 0; } \}#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) \void *operator new(std::size_t size) { \return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \} \void *operator new[](std::size_t size) { \return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); \} \void operator delete(void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \void operator delete[](void * ptr) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \void operator delete(void * ptr, std::size_t /* sz */) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \void operator delete[](void * ptr, std::size_t /* sz */) EIGEN_NO_THROW { Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); } \/* in-place new and delete. since (at least afaik) there is no actual   */ \/* memory allocated we can safely let the default implementation handle */ \/* this particular case. */ \static void *operator new(std::size_t size, void *ptr) { return ::operator new(size,ptr); } \static void *operator new[](std::size_t size, void* ptr) { return ::operator new[](size,ptr); } \void operator delete(void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete(memory,ptr); } \void operator delete[](void * memory, void *ptr) EIGEN_NO_THROW { return ::operator delete[](memory,ptr); } \/* nothrow-new (returns zero instead of std::bad_alloc) */ \EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \void operator delete(void *ptr, const std::nothrow_t&) EIGEN_NO_THROW { \Eigen::internal::conditional_aligned_free<NeedsToAlign>(ptr); \} \typedef void eigen_aligned_operator_new_marker_type;
#else#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
#endif
// 注意接下来这句话:在使用中经常用到它
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(true)
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar,Size) \EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(bool(((Size)!=Eigen::Dynamic) && ((sizeof(Scalar)*(Size))%EIGEN_MAX_ALIGN_BYTES==0)))

在需要重载的类的new delete等上述分配内存的方法中,使用该宏函数,比如

template<typename Derived>
class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
#endif
{public://...public:enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits<Derived>::Alignment>0) };EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)//...
};

当我们使用Eigen时,在类中需要重载内存分配的new delete函数时,加上这句话即可:EIGEN_MAKE_ALIGNED_OPERATOR_NEW ,比如:使用g2o优化时,定义一个顶点,需要使用eigen中的一些底层函数,所以如下:

// 曲线模型的顶点,模板参数:优化变量维度和数据类型
class CurveVertex: public g2o::BaseVertex<4, Eigen::Vector4d> {
public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW  //使用时,加上此句,等于采用eigen中约定的方式重载了该类的new delete等内存分配函数virtual void setToOriginImpl(){_estimate << 0, 0, 0;}virtual void oplusImpl(const double* update) {_estimate += Eigen::Vector4d(update);}virtual bool read(istream & in) {}virtual bool write(ostream & out) const {}};

Eigen中 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF的使用方式_C/C++中的预编译简介相关推荐

  1. c#中的long类型示例_C#中带示例的带符号字节数组

    c#中的long类型示例 C#中的有符号字节数组 (Signed Byte Array in C#) In C#.Net, we can create a signed byte array by u ...

  2. c#中的long类型示例_C#中带示例的无符号字节数组

    c#中的long类型示例 C#中的无符号字节数组 (Unsigned Byte Array in C#) In C#.Net, we can create an unsigned byte array ...

  3. c语言中非法使用void类型_C语言中的数据类型

    为什么需要介绍数据类型 学习语言编程,不用急着写代码,先搞懂基本概念.有了基本概念后,然后再考虑在不同的语言中是如何表达的.不同语言无非就是表达方式不一样而已,万变不离其宗. 每一门语言开始部分中总是 ...

  4. c语言中调整颜色的函数_C语言中的输入输出函数

    点击上方"学士科技",选择"设为星标" 技术干货第一时间送达! 01 字符数据输入输出 字符数据输出函数putchar() C语言中字符数据输出使用的是putc ...

  5. 计算机网络中 数据交换的方式有,计算机网络中的通信数据交换技术探讨

    计算机网络中的通信数据交换技术探讨 摘要:随着科技不断发展,人们对计算机网络技术越来越关注,计算机网络为人们生活带来诸多便利,是科技发展的基础工程.近年来,计算机网络中的通信数据交换技术被广泛应用,网 ...

  6. php中用户验证的方式,在php中进行用户身份验证的最佳方式是什么?

    使用 Sessions.将会话ID存储在cookie中,并将用户的状态存储在服务器端(loggedIn,userId,IP). 澄清您需要存储在会话数组中: > loggedIn:一个关于用户是 ...

  7. c#中索引器是什么_C#中的索引器

    c#中索引器是什么 An Indexer is a special feature of C# to use an object as an array. If you define an index ...

  8. c语言中空格字符怎么表示_C语言中常用的字符串操作函数

    作者:陈太浪 出处:https://home.cnblogs.com/u/TomHe789/ C语言中提供了许多的字符串操作函数,常见的字符串操作函数有以下几种: 1.求字符串长度的函数 原型函数:s ...

  9. mysql中时间的储存方式_数据库 中“日期/时间”存储方式

    Access中: Access 在内部以 双精度浮点数的形式存储"日期/时间"值.每一个此类数值均包含日期和时间两部分.小数点左边的整数部分表示日期.小数点右边的小数部分表示时间. ...

  10. C语言中字符串赋值处理方式,C语言中字符串赋值处理方式

    C语言中,字符串可以赋值给字符指针变量,或者将字符串用字符数组保存.因为c语言没有直接对字符串提供语法糖方面的支持.而且C标准库很多方法处理字符串是以空字符结尾为前提的,这个必须要记住. char * ...

最新文章

  1. 【SpringCloud】简介及其核心组件详解
  2. 58 第一个工程项目(Celery)
  3. poj1190深搜 生日蛋糕
  4. oracle的adr,oracle ADR
  5. easybcd android x86,【图片】不需U盘,简单三步,Win系统变Win+Android双系统!【androidx86吧】_百度贴吧...
  6. AngularDart 现已全面采用 Dart 开发
  7. neo4j cypher_Neo4j:Cypher – Neo.ClientError.Statement.TypeError:不知道如何添加Double和String...
  8. MATLAB电压不平衡,电力系统不对称故障计算的Matlab算法程序
  9. pwm逆变器matlab仿真,PWM逆变器的Matlab仿真分析.doc
  10. 网络数据传输过程分析
  11. linux i386,i486,i586,i686和AMD_64,X86,x86_64后缀的区别
  12. 老掉牙的ArrayList解析它它它又来了
  13. mysql 数据库基础教程(一)
  14. DoIP(一)——基础概念
  15. Unity3d trial version 水印
  16. ContentRoot 和 WebRoot 的区别
  17. android自带浏览器调试,Android 手机浏览器调试使用Chrome进行调试实例详解
  18. PHP webshell、暴力破解
  19. 中国四大名著.html
  20. ruby自动注册163邮箱

热门文章

  1. 在utf8和gb2312中 不同编码情况下,汉字 数字 英文占的字节数?
  2. 程序员提升之排查bug的能力
  3. 【转】完美解除Windows7的驱动程序强制签名限制
  4. CImage 获取图片RGB 、图片高和宽;
  5. POJ1546(进制转换)
  6. Asp.net中把DataTable或DataGrid导出为Excel
  7. 使用C# WinForm实现打印小票的功能
  8. WinForm设置窗体默认控件焦点
  9. maven命令-P 参数引发的思考
  10. 全网最全教你轻松把vue项目部署到IIS服务器