Location类
用于记录类对象产生的位置信息,方便日志的打印。记录的信息主要有,类对象产生的
文件名、所在的
函数名、所在文件的
行号。
Location使用示例
工程
示例工程:https://pan.baidu.com/s/1rbI2hwXpMA-Pb-i-zCdVWA
提取码:cenz
示例
#include <iostream>
#include "location.h"
using namespace std;
class A
{
public:
A(rtc::Location l)
:lt_(l)
{}
void displayLocation()
{
/*获取位置信息*/
cout << lt_.ToString() << endl;
}
private:
rtc::Location lt_; /*记录类A对象产生的位置*/
};
A* func()
{
return new A(RTC_FROM_HERE); /*定义类A对象时,记录产生的位置。*/
}
int main()
{
A* pa = func();
pa->displayLocation();
return 0;
}
运行结果分析如上图,记录了类A对象产生时,所在的函数名、文件名及行号。
Location源码分析
实现原理
通过编译器提供的宏记录类对象产生的位置信息。主要的宏有如下三个:
__FUNCTION__:记录这个宏所在的函数名
__FILE__:记录这个宏所在文件名
__LINE__:记录这个宏所在的行号
使用示例如下:
#include <iostream>
using namespace std;
void func()
{
cout << "__FUNCTION__ = " << __FUNCTION__ << endl;
cout << "__FILE__ = " << __FILE__ << endl;
cout << "__LINE__ = " << __LINE__ << endl;
}
int main()
{
func();
return 0;
}
类的声明
class Location
{
public:
Location(const char* function_name, const char* file_and_line);
Location();
Location(const Location& other);
Location& operator=(const Location& other);
const char* function_name() const { return function_name_; }
const char* file_and_line() const { return file_and_line_; }
std::string ToString() const;
private:
/*存储着对象在哪个函数中产生*/
const char* function_name_;
/*存储着对象在哪个文件的哪一行代码中产生*/
const char* file_and_line_;
};
构造器和赋值运算符重载
/*有参构造器*/
Location::Location(const char* function_name, const char* file_and_line)
: function_name_(function_name), file_and_line_(file_and_line) {}
/*无参构造器*/
Location::Location()
: function_name_("Unknown"), file_and_line_("Unknown") {}
/*拷贝构造器*/
Location::Location(const Location& other)
: function_name_(other.function_name_),
file_and_line_(other.file_and_line_) {}
/*赋值运算符重载*/
Location& Location::operator=(const Location& other)
{
function_name_ = other.function_name_;
file_and_line_ = other.file_and_line_;
return *this;
}
这些代码没有什么难点,就不要解释了。
将位置信息转成字符串
std::string Location::ToString() const
{
char buf[256];
snprintf(buf, sizeof(buf), "%s@%s", function_name_, file_and_line_);
return buf;
}
通过ToString()
函数可以将类的位置信息转成字符串并返回。
RTC_FROM_HERE宏
为了方便使用和明确语义,WebRTC定义了RTC_FROM_HERE
宏,这个宏的作用是定义一个Location类对象。
#define RTC_FROM_HERE RTC_FROM_HERE_WITH_FUNCTION(__FUNCTION__)
#define RTC_FROM_HERE_WITH_FUNCTION(function_name) \
::rtc::Location(function_name, __FILE__ ":" STRINGIZE(__LINE__))
将这两个宏展开后的结果是:
::rtc::Location(__FUNCTION__, __FILE__ ":" STRINGIZE(__LINE__))
关于STRINGIZE
宏,是宏使用中的一个技巧。分析如下:
在C语言和C++中,多个字符串连在一起,可以看成一个字符串。
char buf[] = "China" " is" " great";
cout << buf << endl;
运行结果是:China is great
#define str(x) "x"
cout << str(123) << endl;
运行结果是:x
#define str(x) x
cout << str(123) << endl;
运行结果是:123
#define str(x) "aaa"x"bbb"
cout << str(123) << endl;
运行出错
#define str(x) "aaa"#x"bbb"
cout << str(123) << endl;
运行结果是:aaa123bbb
在宏函数中#
可以将参数字符串化,"aaa"#x"bbb"
经宏替换后为"aaa""123""bbb"
,也就等价于"aaa123bbb"
。
会到待分析的码中,STRINGIZE(__LINE__)
宏展开过程如下:
#define STRINGIZE_NO_EXPANSION(x) #x
#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x)
展开后的结果为:
#__LINE__
把所有的宏展开以后结果为:
::rtc::Location(__FUNCTION__, __FILE__ ":" "__LINE__")
之所以大费周折的使用STRINGIZE
宏,是因为__FILE__是字符串,而__LINE__是整数,为了将它们连接成字符串,需要将__LINE__字符化,字符化后再连接成字符串。
小结
本文分析了Location类的实现方式,主要分析了编译器提供的宏和一些宏使用的技巧。