如何用C++ constexpr函数返回编译期常量字符串字面量
编译期从
__FILE__提取独立文件名(MSVC下实现) 可行,但原实现无法达成目标,核心原因是:你的函数返回的是__FILE__原字符串字面量的子串指针,编译器不会自动将该子串单独提取为新的字符串字面量,因此完整路径仍会保留在二进制中。要实现仅保留文件名的目标,需通过编译期构造独立字符数组的方式生成文件名。
问题分析
__FILE__是编译器注入的完整路径字符串字面量,原函数返回的指针指向该字面量的某一位置。即使编译器在编译期计算出了指针位置,也不会主动将子串剥离为独立字面量——因为指针依赖原字符串的存在,所以完整路径会被保留,无法达到你想要的效果。
解决方案:编译期构造独立文件名数组
通过constexpr构造一个仅包含文件名的字符数组,编译器会在编译期直接生成该数组的常量数据,原__FILE__的完整路径会因未被实际引用而被优化移除(需配合MSVC的优化设置)。
示例代码(兼容跨平台)
#include <iostream> constexpr auto get_filename() { // 定位文件名起始位置 const char* file = __FILE__; const char* name_start = file; while (*file != '\0') { if (*file == '\\' || *file == '/') { name_start = file + 1; } ++file; } // 编译期计算文件名长度 constexpr size_t name_len = []{ const char* f = __FILE__; const char* s = f; while (*f != '\0') { if (*f == '\\' || *f == '/') { s = f + 1; } ++f; } return static_cast<size_t>(f - s); }(); // 编译期构造文件名数组 char filename[name_len + 1]{}; for (size_t i = 0; i < name_len; ++i) { filename[i] = name_start[i]; } filename[name_len] = '\0'; return filename; } int main() { std::cout << get_filename() << std::endl; return 0; }
MSVC优化配置要求
确保以下设置生效:
- 开启最高优化级别:
/O2(Release模式默认开启) - 启用引用优化:
/OPT:REF(默认开启,会移除未被引用的全局数据,包括原__FILE__完整路径) - 关闭"保留未使用的符号"相关选项,避免原字符串被保留
说明
- 代码同时处理Windows的
\\路径分隔符和类Unix的/分隔符,具备跨平台兼容性。 - 编译期构造的字符数组会直接嵌入二进制,仅包含文件名内容,原完整路径不会出现在最终可执行文件中。
内容的提问来源于stack exchange,提问作者Arush Agarampur
相关产品推荐
相关产品推荐

