调试神器:__FILE__和__FUNC__和__DATA__以及##等命令

在程序调试过程中,为了跟踪程序执行的顺序,往往会在程序中输出log信息,例如:

void function(void){
    cout<<"I am here -> function"
}
对于中间输出的这行代码而言,没有任何重用性,在另一个程序function2中,我们必须要修改成如下:
void function2(void){
    cout<<"I am here -> function2"
}

是否有更好用的代码呢?


接下来为大家介绍几个神奇的命令,它们属于内置变量,无需添加头文件即可使用!



__DATE__、__TIME__、__FILE__、__FUNCTION__、__LINE__

#include 

using namespace std;

void hello()
{	
	cout << __DATE__ << endl;		//以“Mmm dd yyyy”形式保存月日年字符串;
	cout << __TIME__ << endl;		//以“hh:mm:ss”形式保存的时分秒字符串;
	cout << __FILE__ << endl;		//当前文件的绝对路径;
	cout << __FUNCTION__ << endl;	//当前所处函数的函数名;
	cout << __LINE__ << endl;		//本代码在文件中的行索引;
}
输出结果见下图:

调试神器:__FILE__和__FUNC__和__DATA__以及##等命令_第1张图片


原理:

__DATE__、__TIME__、__FILE__、__FUNCTION__、__LINE__属于预定义宏,在系统编译过程中替代成为指定字符串


和普通宏不同的是,普通宏需要用户显式定义内容,如#define PI 3.1415,如上命令是在系统编译过程中,根据语法分析得到其所在函数、文件的信息,而替换成不同的字符串。如__FUNCTION__在hello();函数中代表字符串hello,而在function();函数中代表字符串function,从而实现了代码的重用,为调试提供方便。


##命令

##命令代表连接两个字符串,如下:

#define CON(x,y) x##y

int main(void){
    int num = CON(1,2);                        //num等于数字3;
    string str = CON("hello","world");         //str等于字符串"helloworld";
}

注意,##是在编译过程中将两个参数连接成一个字符串,所以需要保证连接后的字符串是一个常量字符串或者一个已经定义的变量;

	int ConnectIndex0 = 0;
	int index = 0;
	CON(ConnectIndex, 0) = 10;	    //正确;
        CON("ConnectIndex", "0") = 10;  //错误1;
	CON(ConnectIndex, index) = 10;  //错误2;


上面代码错误的原因在于:

错误1:因为不能对字符串“ConnectIndex0”赋值;

错误2:因为不存在ConnectIndexindex这个变量;


是不是感觉很鸡肋?

记得之前见过一个用处:将##命令用在内部类和外部类之间的,暂时找不到出处了...

以后找到了再补充!


#命令和#@命令

#x     命令:在参数x两端加上双引号变成字符串;

#@x 命令:在参数x两端加上单引号;


参考文献:

【1】C/C++ 打印文件名、行号、函数名的方法

【2】VC++ __FUNCTION__的实现原理是什么?能通过这个拿到整个的函数列表吗?

【3】__func__ value difference between C and C++

【4】C语言宏定义##连接符和#符的使用






你可能感兴趣的:(C++原理)