提供手机自适应网站,电影资源网站开发,wordpress文章序号排列,怎么做加密货币网站1 __FILE__ 和 __LINE__
你一定看过这样的代码#xff1a;
printf(Internal error at \%s\ on line %d.\n, __FILE__, __LINE__); 这行代码的作用就是打印出 printf() 函数调用发生时所在的源代码文件名#xff08;包含路径#xff09;和这行代…1 __FILE__ 和 __LINE__
你一定看过这样的代码
printf(Internal error at \%s\ on line %d.\n, __FILE__, __LINE__); 这行代码的作用就是打印出 printf() 函数调用发生时所在的源代码文件名包含路径和这行代码在这个源代码文件中的行数。__FILE__ 和 __LINE__ 是 C 语言定义的标准预定义宏编译器会在编译阶段将其展开替换成实际的位置信息。C99 又增加了一个表示当前函数名的宏就是 __func__有一些编译器比如 GCC 也会使用 __FUNCTION_除了一些细微的语义差别之外它们的内容展开结果是一样的。
void ProcessLog(t) {printf(error at function: %s\n, __func__); //error at function: ProcessLog
}2 #line 指令
正常情况下__FILE__ 和 __LINE__ 表示的就是调用发生的地方的信息但是也有例外。在一些复杂系统的编译体系中部分源代码是通过脚本动态生成的根据 OS、依赖库或其他信息动态生成支撑层代码这种情况下预编译程序在替换这两个宏的时候转换的位置信息与最终的源代码信息可能不一致导致 C 的代码在脚本中的实际位置可能存在偏差。另外就是源代码文件的名称可能是动态拼接出来的并不是预处理程序所感知的那个文件名使得__FILE__的结果也与实际文件名不一致 。
在这种情况下为了让编译器最终得到准确的信息需要使用#line预编译指令调整文件名和代码行数信息这个指令的命令格式是其中 filename 参数是可选参数
#line linenum [filename]linenum 是一个非负整数表示从这个位置开始这个文件的代码行从 linenum 指定的数字开始计数。比如这个例子
#line 200 int main() {printf(Internal error at line %d\n, __LINE__);
}printf() 函数输出的结果是
Internal error at line 203 因为#line是预编译指令它只影响从这行指令之后的代码中的预编译宏对这条指令代码位置之前出现的__FILE__ 和 __LINE__ 没有影响比如这个例子
void ProcessLog() {printf(error at function %s (%d).\n, __func__, __LINE__);
}#line 200 int main() {ProcessLog();printf(Internal error at line %d.\n, __LINE__);
}最终的输出结果是
error at function ProcessLog (15).
Internal error at line 204.可见ProcessLog() 函数中的__LINE__没有受到这条指令的影响。
如果要调整文件的名字可以这样使用#line指令
#line 200 testfile.cppint main() {printf(Internal error at \%s\ on line %d.\n, __FILE__, __LINE__);
}最后的输出结果是
Internal error at E:\workspace\01 Test\sl\testfile.cpp on line 203.3 std::source_location
C 也从 C 继承了这些预定义宏在 C 代码中仍然可以使用它们。不过C 20 提供了一个名为 std::source_location 的类用于表示源代码相关的信息比如文件名、行号、函数名等等。传统上使用__FILE__ 和 __LINE__的地方都可以用这个类代替并且使用 std::source_location 可以获得更多信息是更好的选择。
std::source_location 的基本用法就是通过这个类的静态函数 current() 可以获得当前调用位置的信息然后使用 file_name()、line() 等成员方法获取这些信息
void ProcessLog(const std::string_view message) {const std::source_location location std::source_location::current();std::cout file: location.file_name() ( location.line() : location.column() ) location.function_name() : message std::endl;
} 除了多了一个 column 信息std::source_location 的好处在什么地方好处就是 std::source_location 能表示更多信息比如函数传统的__func__只能得到函数的基本信息即函数的名称而 std::source_location 类的 function_name() 可以获得更多的信息
void ProcessLog(const std::string_view message) {const std::source_location location std::source_location::current();std::cout function: location.function_name() , message \n;
}int main(int, char* []) {ProcessLog(Message);
}上面的代码输出的信息是
function: void log(std::string_view), Message函数名包含详细的签名信息。对于函数模板还会输出模板参数的替换和匹配信息比如这段代码
using namespace std::literals;template typename T
void ProcessLog(T x) {const std::source_location location std::source_location::current();std::cout function: location.function_name() , x \n;}int main(int, char* []) {ProcessLog(Messages);
}代码中的函数模板替换后模板参数 T 的类型就是 std::stringfunction_name() 的输出信息也包含这部分内容
function: void ProcessLog(T) [with T std::basic_stringchar], Message 最后说重点第 2 节介绍的#line指令对 std::source_location 也会产生影响所以你应该能猜到是什么原因。还有一点就是目前并不是所有的编译器都支持输出更详细的函数信息尤其是函数模板参数的替换结果经过测试GCC 11 以后的版本支持。
4 参考资料
https://en.cppreference.com/w/cpp/preprocessor/line
https://gcc.gnu.org/onlinedocs/cpp/Line-Control.html#Line-Control
https://en.cppreference.com/w/cpp/utility/source_location
关注作者的算法专栏 https://blog.csdn.net/orbit/category_10400723.html
关注作者的出版物《算法的乐趣第二版》 https://www.ituring.com.cn/book/3180