__FILE__
在C语言中显示文件的完整路径。有没有办法缩短路径并只获取文件名?我的意思是,不要显示完整路径,只显示文件名。/full/path/to/file.c
我明白了。
to/file.c
或者
file.c
__FILE__
在C语言中显示文件的完整路径。有没有办法缩短路径并只获取文件名?我的意思是,不要显示完整路径,只显示文件名。/full/path/to/file.c
to/file.c
或者
file.c
试一试
#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
对于 Windows 系统,请使用 '\\' 而不是 '/'.
strrchr("/" __FILE__, '/') + 1
。通过在 __FILE__
前面添加 /
,可以确保 strrchr 找到某些内容,因此不再需要条件 ?:。 - ɲeuroburɳstrchr
和 strrchr
的调用,更不用说对 __FILENAME__
宏的引用了。如果不能,这个解决方案就是完全臃肿的。 - l33t如果您正在使用cmake,这里有一个提示。来自于:http://public.kitware.com/pipermail/cmake/2013-January/053117.html
我将这个提示复制到这个页面上:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"
其中$(SOURCE_PREFIX)
是您想要移除的前缀。
然后使用__FILENAME__
代替__FILE__
。
__FILE__
不是一个简单的预处理器符号,它会变成当前文件,并常用于输出当前文件(头文件或源模块)的名称。而 __FILENAME__
只会有最外层的源文件名。 - nhed__FILE__
会占用大量的代码空间。 - mrtumnusGCC 8 现在具有 -fmacro-prefix-map
和 -ffile-prefix-map
选项:
-fmacro-prefix-map=old=new
当预处理位于目录 old 中的文件时,将
__FILE__
和__BASE_FILE__
宏扩展为如果这些文件实际上位于目录 new 中一样。通过使用.
作为 new 来将绝对路径更改为相对路径,从而使生成的构建更可重复且与位置无关。此选项也会影响编译期间的__builtin_FILE()
。另请参见-ffile-prefix-map
。
-ffile-prefix-map=old=new
当编译位于目录 old 中的文件时,将它们的任何引用记录到编译结果中,就像这些文件实际上位于目录 new 中一样。指定此选项等效于指定所有单独的
-f*-prefix-map
选项。这可以用于创建更可重复且与位置无关的构建。另请参见-fmacro-prefix-map
和-fdebug-prefix-map
.
如果您设置-ffile-prefix-map
(-fdebug-prefix-map
)的路径无效,则会破坏调试功能,除非您告诉调试器如何进行映射(对于gdb: set substitue-path
, 对于vscode: "sourceFileMap"
)。
如果您的意图仅仅是清理 __FILE__
,则只需使用-fmacro-prefix-map
。
例如:我的Jenkins构建中,我将添加-ffile-prefix-map=${WORKSPACE}/=/
,还有另一个用于删除本地开发软件包安装前缀。
注意:不幸的是,-ffile-prefix-map
和-fmacro-prefix-map
选项仅在GCC 8及更高版本中可用。例如,在GCC 5中,我们只有-fdebug-prefix-map
,它不会影响__FILE__
。
-ffile-prefix-map
确实隐含了-fdebug-prefix-map
和-fmacro-prefix-map
选项。请参见https://reproducible-builds.org/docs/build-path/上的参考文献。跟踪`-fmacro-prefix-map`和`-ffile-prefix-map`的GCC错误是https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70268。 - Lekensteyn__FILE__
宏中,完全删除目录,并仅显示从您的源目录开始的文件名。# The additional / is important to remove the last character from the path.
# Note that it does not matter if the OS uses / or \, because we are only
# saving the path size.
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
__FILENAME__
宏,该宏只是将源路径大小添加到__FILE__
宏中:#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
__FILE__
宏即可。这是有效的,因为__FILE__
路径始终以您的CMake源目录路径开头。通过从__FILE__
字符串中删除它,预处理器将负责指定正确的文件名,并且所有内容都将相对于您的CMake项目的根目录。__FILE__
一样高效,因为__FILE__
和SOURCE_PATH_SIZE
均为已知在编译时的常量,因此可以被编译器优化掉。CMAKE_BUILD_DIR
变量而不是CMAKE_SOURCE_DIR
。__FILE__
是指向字节数组的指针。因此,添加数字字面量只是指针加法。非常聪明的@RenatoUtsch。 - Daniel__FILE__
宏和SOURCE_PATH_SIZE宏都是在编译时已知的常量。我期望现代优化编译器能够检测到字符串的一部分未被使用,并将其从二进制文件中删除。无论如何,我认为这几个字节不会对二进制文件大小产生显著影响,所以我并不关心它。 - RenatoUtschC++11
msvc2015u3,gcc5.4,clang3.8.0
template <typename T, size_t S>
inline constexpr size_t get_file_name_offset(const T (& str)[S], size_t i = S - 1)
{
return (str[i] == '/' || str[i] == '\\') ? i + 1 : (i > 0 ? get_file_name_offset(str, i - 1) : 0);
}
template <typename T>
inline constexpr size_t get_file_name_offset(T (& str)[1])
{
return 0;
}
'
int main()
{
printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
}
当代码生成编译时偏移量时:
gcc
: at least gcc6.1 + -O1
msvc
: put result into constexpr variable:
constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
printf("%s\n", file);
clang
: insists on not compile time evaluation
有一个技巧可以强制所有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__))]);
}
#define LEAF(FN) (&FN[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(FN))])
,并像这样使用它printf("%s\n", LEAF(__FILE__));
。 - psyched#define __FILENAME__ (__FILE__ + get_file_name_offset(__FILE__))
- automorphic至少对于gcc编译器而言,__FILE__
的值是编译器命令行中指定的文件路径。如果像这样编译file.c
:
gcc -c /full/path/to/file.c
__FILE__
将展开为 "/full/path/to/file.c"
。如果您这样做:
cd /full/path/to
gcc -c file.c
然后__FILE__
将只扩展为"file.c"
。
这可能实用,也可能不实用。
C标准不要求此行为。它关于__FILE__
的说明仅为“当前源文件的假定名称(字符字符串文字)”。
另一种选择是使用#line
指令。它可以覆盖当前行号,并可选地覆盖源文件名。如果您想覆盖文件名但保留行号,请使用__LINE__
宏。
例如,您可以在file.c
顶部附近添加此代码:
#line __LINE__ "file.c"
唯一的问题是它将指定的行号分配给下一行,#line
的第一个参数必须是 数字序列,因此你不能做像这样的事情
#line (__LINE__-1) "file.c" // This is invalid
确保#line
指令中的文件名与实际文件名匹配是留给读者练习的。
至少对于gcc来说,这也会影响诊断消息中报告的文件名。
__LINE__
的值减1。因此,在第x行写入的__LINE__
会被评估为x-1
。至少在gcc 5.4中是如此。 - elklepo#line __LINE__-1, "file.c"
。我会更新我的答案。 - Keith Thompson#line 2 "name.cpp"
即可。另外需要注意的是,在包含该文件的其他文件中不会被污染(至少在 MSVC 上是这样的)。 - Matt Eding这里是纯粹的编译时解决方案。它基于这样一个事实:字符串字面量的sizeof()
返回其长度+1。
#define STRIPPATH(s)\
(sizeof(s) > 2 && (s)[sizeof(s)-2] == '/' ? (s) + sizeof(s) - 1 : \
sizeof(s) > 3 && (s)[sizeof(s)-3] == '/' ? (s) + sizeof(s) - 2 : \
sizeof(s) > 4 && (s)[sizeof(s)-4] == '/' ? (s) + sizeof(s) - 3 : \
sizeof(s) > 5 && (s)[sizeof(s)-5] == '/' ? (s) + sizeof(s) - 4 : \
sizeof(s) > 6 && (s)[sizeof(s)-6] == '/' ? (s) + sizeof(s) - 5 : \
sizeof(s) > 7 && (s)[sizeof(s)-7] == '/' ? (s) + sizeof(s) - 6 : \
sizeof(s) > 8 && (s)[sizeof(s)-8] == '/' ? (s) + sizeof(s) - 7 : \
sizeof(s) > 9 && (s)[sizeof(s)-9] == '/' ? (s) + sizeof(s) - 8 : \
sizeof(s) > 10 && (s)[sizeof(s)-10] == '/' ? (s) + sizeof(s) - 9 : \
sizeof(s) > 11 && (s)[sizeof(s)-11] == '/' ? (s) + sizeof(s) - 10 : (s))
#define __JUSTFILE__ STRIPPATH(__FILE__)
请随意扩展条件运算符级联到项目中最合理的文件名。路径长度并不重要,只要您从字符串的结尾检查得足够远即可。
我会尝试使用宏递归来获取一个类似的没有硬编码长度的宏...
-O1
。 - Digital Traumasizeof(s)>2
。而且,在我的编译中,它在-Os时无法正常工作。完整路径字符串存在于输出二进制文件中。 - mrtumnus最近的Clang编译器有一个__FILE_NAME__
宏(请参见这里)。
__FILE__
会使用相对路径而不是绝对路径。虽然它更短,但并不是一个“无路径文件名”的解决方案。 - Cem PolatUseFullPaths
)默认为true
,除非在更本地的级别(例如在项目文件中)被覆盖。请参阅Microsoft.Cl.Common.props
... - 0xC0000022L我使用了与 @Patrick 的答案相同的解决方案多年。
当完整路径包含符号链接时,它会有一个小问题。
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
-Wno-builtin-macro-redefined
可以抑制编译器对重新定义__FILE__
宏的警告。
对于不支持此选项的编译器,请参考下面的鲁棒方法。
从文件路径中去除项目路径是你的真实需求。你不希望浪费时间去查找header.h
文件,src/foo/header.h
还是src/bar/header.h
。
我们应该在cmake
配置文件中取消__FILE__
宏。
这个宏在大多数现有的代码中都有使用。简单地重新定义它可以让您自由操作。
像gcc
这样的编译器从命令行参数中预定义了这个宏。而完整路径写在cmake
生成的makefile
中。
需要在CMAKE_*_FLAGS
中硬编码。
有一些命令可以在一些较新版本中添加编译器选项或定义,如add_definitions()
和add_compile_definitions()
。这些命令将在应用于源文件之前解析subst
等制作函数。这不是我们想要的。
-Wno-builtin-macro-redefined
的鲁棒方法。include(CheckCCompilerFlag)
check_c_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
set(*_FLAGS ... -D__FILE__=...)
这行中删除该编译器选项。__FILE__
来生成头文件中定义的内联函数的诊断信息,则运行时诊断将报告传递给编译器的文件名,而不是包含文件的名称,而行号将指向包含文件。 - chqrlie#define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args)
。当使用 LOG()
宏时,您不希望在消息中看到 log.h
。毕竟,__FILE__
宏在每个 C/Cpp 文件(编译单元)中都会被扩展,而不是包含的文件。 - Levi.G
__FILE__
的内容。因此,不要使用gcc /full/path/to/file.c
,而是尝试cd /full/path/to; gcc file.c; cd -;
。当然,如果你依赖于gcc的当前目录来设置包含路径或输出文件位置,则需要更多的修改。编辑:gcc文档表明它是完整路径,而不是输入文件名参数,但在Cygwin上的gcc 4.5.3中,我看到的并非如此。因此,你可以在Linux上尝试一下。 - Steve Jessop__FILE__
被打印为../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.c
,我想知道gcc编译文件的位置,以便该文件相对于所示的位置定位。 - Chan Kim