C语言中可用的标准预定义宏__FILE__显示文件的完整路径。有办法缩短这条路吗?我的意思是
/full/path/to/file.c
我看到
to/file.c
or
file.c
C语言中可用的标准预定义宏__FILE__显示文件的完整路径。有办法缩短这条路吗?我的意思是
/full/path/to/file.c
我看到
to/file.c
or
file.c
当前回答
一个简短的,适用于Windows和*nix的答案:
#define __FILENAME__ std::max<const char*>(__FILE__,\
std::max(strrchr(__FILE__, '\\')+1, strrchr(__FILE__, '/')+1))
其他回答
c++ 11 msvc2015u3、gcc5.4 clang3.8.0 模板<typename T, size_t S> (const T (& str)[S], size_t i = S - 1) { 返回(str[i] == '/' || str[i] == '\\') ?I + 1:(I > 0 ?Get_file_name_offset (str, I - 1): 0); } template <typename T> (T (& str)[1]) { 返回0; }
'
int main()
{
printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
}
代码在以下情况下产生编译时偏移量:
gcc:至少gcc6.1 + -O1 Msvc:将结果放入constexpr变量: constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)]; printf (" % s \ n ",文件); Clang:坚持不编译时计算
有一个技巧可以强制所有3个编译器进行编译时间计算,即使在调试配置中禁用优化:
namespace utility {
template <typename T, T v>
struct const_expr_value
{
static constexpr const T value = v;
};
}
#define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value
int main()
{
printf("%s\n", &__FILE__[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(__FILE__))]);
}
https://godbolt.org/z/u6s8j3
下面是一个适用于Linux(路径'/')和Windows('\'和'/'混合)的可移植函数。使用gcc, clang和vs编译。
#include <string.h>
#include <stdio.h>
const char* GetFileName(const char *path)
{
const char *name = NULL, *tmp = NULL;
if (path && *path) {
name = strrchr(path, '/');
tmp = strrchr(path, '\\');
if (tmp) {
return name && name > tmp ? name + 1 : tmp + 1;
}
}
return name ? name + 1 : path;
}
int main() {
const char *name = NULL, *path = NULL;
path = __FILE__;
name = GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path ="/tmp/device.log";
name = GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path = "C:\\Downloads\\crisis.avi";
name = GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path = "C:\\Downloads/nda.pdf";
name = GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path = "C:/Downloads\\word.doc";
name = GetFileName(path);
printf("path: %s, filename: %s\n", path, name);
path = NULL;
name = GetFileName(NULL);
printf("path: %s, filename: %s\n", path, name);
path = "";
name = GetFileName("");
printf("path: %s, filename: %s\n", path, name);
return 0;
}
标准输出:
path: test.c, filename: test.c
path: /tmp/device.log, filename: device.log
path: C:\Downloads\crisis.avi, filename: crisis.avi
path: C:\Downloads/nda.pdf, filename: nda.pdf
path: C:/Downloads\word.doc, filename: word.doc
path: (null), filename: (null)
path: , filename:
只是希望改进一下FILE宏:
#定义文件(strrchr(__FILE__, '/') ?strrchr __FILE __, '/') + 1: strrchr __FILE __, '\\') ?strrchr(__FILE__, '\\') + 1: __FILE__)
这捕获/和\,像Czarek Tomczak要求的,这在我的混合环境中工作得很好。
I think this is better than using strrchr function. strfnchr will search last delemeter '/' and get filename from __FILE__ and you can use __FILE__NAME__ instead __FILE__ for get file name without full file path. strrchr solution searching filename twice per use. but this code is just 1 time search. And it works effectively even if there is no seperater '/' in __FILE__. You can use it by replacing it with \ as needed. The source code of strfnchr was improved by using the source code of strrchr below. I think it will work more effectively than strrchr. https://code.woboq.org/userspace/glibc/string/strrchr.c.html
inline const char* strfnchr(const char* s, int c) {
const char* found = s;
while (*(s++)) {
if (*s == c)
found = s;
}
if (found != s)
return found + 1;
return s;
}
#define __FILE_NAME__ strfnchr(__FILE__, '/')
GCC 8现在有-fmacro prefix-map和- file-prefix-map选项:
-fmacro-prefix-map = =新老 当预处理位于旧目录下的文件时,展开__FILE__和__BASE_FILE__宏,就好像文件位于新目录下一样。这可用于将绝对路径更改为相对路径。对于new,这可以导致更可重复的构建,这些构建是独立于位置的。该选项还会在编译期间影响__builtin_FILE()。参见- file-prefix-map。
-ffile-prefix-map = =新老 当编译位于旧目录中的文件时,记录所有引用 对他们来说,编译的结果就好像文件就在里面一样 改为新建目录。指定此选项相当于 指定所有单独的-f*-prefix-map选项。可以使用这个 制作独立于位置的可重复构建。另请参阅 -fmacro prefix-map和-fdebug-prefix-map。
为- file-prefix-map (-fdebug-prefix-map)设置无效路径将中断调试,除非你告诉调试器如何映射回去。(gdb: set replace -path, vscode: "sourceFileMap")。
如果你的意图只是清理__FILE__,只需使用-fmacro prefix-map。
例子: 所以对于我的Jenkins构建,我将添加- file-prefix-map=${WORKSPACE}/=/,并删除本地开发包安装前缀。
不幸的是- file-prefix-map和-fmacro prefix-map选项仅在GCC 8以后可用。例如,对于GCC 5,我们只有-fdebug-prefix-map,它不影响__FILE__。