回顾复习一些常见的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进制数为一个字节。