C++

C++宏展开问题

C++常见问题(三)

Posted by Francis-wu on November 14, 2018

回顾复习一些常见的C++问题,以及一些没有仔细考虑过的地方。(任何问题欢迎邮件:admin@franciswu.top

今天偶然遇到的问题,学到了~

1、#define的定义

#define 指令定义标识符为宏,即指示编译器以替换列表替换标识符的所有后继出现。

这里主要讨论仿函数宏,常量替换的就不谈了。

仿函数宏以替换列表替换每次出现的被定义标识符,可选的接受一定量实参,然后替换替换列表中任何形参的对应出现。

2、宏展开替换的时机

C++编译主要分为,预编译,编译,汇编,链接四个步骤,前面讲过。

预编译的主要任务:

  • 文件包含

    可以把源程序中的#include扩展为文件正文,即把包含的.h文件找到并展开到#include所在处。

  • 条件编译

    预处理器根据#if#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常吧排除在外的语句转换为空行。

  • 宏展开

    预处理器将远程与文件中出现的对宏引用展开成相应的宏定义,即#define功能。经过预处理器处理的源程序与之前的源程序有所不同。

    在这个阶段进行的工作只是纯粹的替换与展开,没有任何计算功能。

3、常见误解

#include <iostream>
using namespace std;

#define SQ(X) X*X

int main()
{
	int c = SQ(2+1);
	int d = SQ(2+1)/SQ(2+1);

	cout<<d<<endl;
	system("pause");
}

一般会习惯性的认为c的值为9,d的值为1。这是不对的。正确的值是c为5,d为7。

预编译的时候会将仿函数的参数作为纯碎的字符串进行展开,并不会在这个阶段进行计算,常量的计算会在编译期完成。

证明:打开预处理文件,对应的同名.i文件。

展开后的预处理代码为:

int main()
{
	int c = 2+1*2+1;
	int d = 2+1*2+1/2+1*2+1;

	cout<<d<<endl;
	system("pause");
}

4、define中的三个特殊符号:#,##,#@

  • #define Conn(x,y) x##y

    • int n = Conn(123,456); /* 结果为n=123456 */
    • char* str = Conn(“abc”, “def”);/* 结果为str=“abcdef” */
  • #define ToChar(x) #@x

    • char a = ToChar(1);// a=’1’
  • #define ToString(x) #x

    • char* str = ToString(123123);// 作用是给参数加上双引号 str=”123123”

5、常用宏定义

  • 防止头文件重复包含 略

  • 得到指定地址上的一个字或字节

    • #define MEM_B(x) (*((byte*)(x)))
    • #define MEM_W(x) (*((WORD*)(x)))

    demo:

     	#include <iostream>
        #include <windows.h>
        #define MEM_B(x) (*((byte*)(x)))
        #define MEM_W(x) (*((WORD*)(x)))
        int main()
        {
            int bTest = 0x123456;
            byte m = MEM_B((&bTest));/*m=0x56*/
            int n = MEM_W((&bTest));/*n=0x3456*/
            return 0;
        }
    

    值为什么取出来是m=0x56,n=0x3456,如图:

一个byte是一个字节,一个word是两个字节。内存查看以16进制显示,每一个16进制数要4位二进制显示,2个16进制数为一个字节。