__FILE__ 宏显示完整路径
C 中可用的标准预定义宏 __FILE__
显示文件的完整路径。有什么方法可以缩短路径并仅获取文件名吗?我的意思是,而不是
/full/path/to/file.c
我看到
to/file.c
或
file.c
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
使用 basename() 函数,或者,如果您使用的是 Windows,_splitpath()。
还可以在 shell 中尝试
man 3 basename
。Use the basename() function, or, if you are on Windows, _splitpath().
Also try
man 3 basename
in a shell.如果您将
CMAKE
与 GNU 编译器一起使用,则此global
定义可以正常工作:If you are using
CMAKE
with GNU compiler thisglobal
define works fine:@red1ynx 建议的稍有变化是创建以下宏:
在每个 .c(pp) 文件中添加:
然后您可以引用
THIS_FILE_NAME
而不是__FILE__
:这意味着每个 .c(pp) 文件都会执行一次构造,而不是每次引用宏时执行一次。
它仅限于从 .c(pp) 文件使用,并且无法从头文件中使用。
A slight variation on what @red1ynx proposed would to be create the following macro:
In each of your .c(pp) files add:
Then you can refer to
THIS_FILE_NAME
instead of__FILE__
:This means the construction is performed once per .c(pp) file instead of each time the macro is referenced.
It is limited to use only from .c(pp) files and would be unusable from header files.
只是希望稍微改进一下 FILE 宏:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
这会捕获 / 和 \,就像 Czarek Tomczak 所要求的那样,这在我的混合环境。
just hope to improve FILE macro a bit:
#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
this catches / and \, like Czarek Tomczak requested, and this works great in my mixed environment.
我做了一个宏
__FILENAME__
以避免每次都剪切完整路径。问题是将生成的文件名保存在 cpp 局部变量中。通过在 .h 文件中定义静态全局变量可以轻松完成此操作。
此定义在包含 .h 的每个 .cpp 文件中给出了单独且独立的变量。
为了成为多线程证明,值得使变量也成为线程本地(TLS)。
一个变量存储文件名(已缩小)。另一个保存
__FILE__
给出的非剪切值。 h 文件:宏本身调用带有所有逻辑的方法:
函数是这样实现的:
removePath() 可以用不同的方式实现,但快速和简单的似乎是使用 strrchr:
I did a macro
__FILENAME__
that avoids cutting full path each time. The issue is to hold the resulting file name in a cpp-local variable.It can be easily done by defining a static global variable in .h file.
This definition gives separate and independent variables in each .cpp file that includes the .h.
In order to be a multithreading-proof it worth to make the variable(s) also thread local (TLS).
One variable stores the File Name (shrunk). Another holds the non-cut value that
__FILE__
gave. The h file:The macro itself calls method with all the logic:
And the function is implemented this way:
The removePath() can be implemented in different ways, but the fast and simple seems to be with strrchr:
尝试
在源文件中的 include 语句之后添加,并添加
到源文件的末尾。
Try
after the include statements in your source file and add
at the end of your source file.
这是一个可移植函数,适用于 Linux(路径“/”)和 Windows(“\”和“/”的混合)。
使用 gcc、clang 和
标准输出进行编译:
Here is a portable function that works for both Linux (path '/') and Windows (mix of '\' and '/').
Compiles with gcc, clang and vs.
Standard output:
如果您最终在此页面上寻找一种方法来从您正在发送的二进制文件中删除指向难看的构建位置的绝对源路径,那么下面的内容可能会满足您的需求。
虽然这并不能准确地给出作者所表达的愿望的答案,因为它假设使用 CMake,但它已经非常接近了。遗憾的是,没有人早些时候提到这一点,因为它可以节省我大量的时间。
将上述变量设置为
ON
将生成以下格式的构建命令:因此,
__FILE__
宏将解析为../../src/path/to /source.c
CMake 文档
注意文档页面上的警告:
不能保证在所有情况下都有效,但在我的情况下有效 - CMake 3.13 + gcc 4.5
If you ended up on this page looking for a way to remove absolute source path that is pointing to ugly build location from the binary that you are shipping, below might suit your needs.
Although this doesn't produce exactly the answer that the author has expressed his wish for since it assumes the use of CMake, it gets pretty close. It's a pity this wasn't mentioned earlier by anyone as it would have saved me loads of time.
Setting above variable to
ON
will generate build command in the format:As a result,
__FILE__
macro will resolve to../../src/path/to/source.c
CMake documentation
Beware of the warning on the documentation page though:
It is not guaranteed to work in all cases, but worked in mine - CMake 3.13 + gcc 4.5
适用于 Windows 和 *nix 的简短有效答案:
A short, working answer for both Windows and *nix:
在 MSVC 中,将 FILENAME 宏作为 FILENAME=%(FileName)%(Extension) 添加到 C++ 项目的预处理器定义中。恐怕这完全就是一个编译器杀手。不知怎的,它破坏了并行构建。
In MSVC, add FILENAME macro as FILENAME=%(FileName)%(Extension) to the Preprocessor Definitions of the C++ project. I'm afraid this is completely a compiler killer. Somehow it breaks parallel build.
这是一个适用于没有字符串库的环境(Linux 内核、嵌入式系统等)的解决方案:
现在只需使用
FILENAME
而不是__FILENAME__
。是的,这仍然是一个运行时的事情,但它确实有效。Here's a solution that works for environments that don't have the string library (Linux kernel, embedded systems, etc):
Now just use
FILENAME
instead of__FILENAME__
. Yes, it's still a runtime thing but it works.red1ynx 的答案经过调整,甚至更加“臃肿”:
如果我们找到反斜杠,我们就会根据反斜杠进行拆分。否则,按正斜杠分割。够简单的。
几乎任何替代方案都会更干净(在我看来,C++ constexpr 实际上是这里的黄金标准)。但是,如果您使用的某些编译器中 __BASE_FILE__ 不可用,这可能会有所帮助。
A tweaked, even more "bloated" version of red1ynx's answer:
If we find backslashes, we split on backslashes. Otherwise, split on forward slash. Simple enough.
Just about any alternative would be cleaner (A C++ constexpr is really the gold standard here, in my opinion). However, this may be helpful if you're using some compiler where
__BASE_FILE__
isn't available.我认为这比使用 strrchr 函数更好。
strfnchr 将搜索最后一个 delemeter '/' 并从 __FILE__ 获取文件名
您可以使用
__FILE__NAME__
代替__FILE__
来获取没有完整文件路径的文件名。strrchr 解决方案每次使用都会搜索文件名两次。但这段代码只是搜索1次。
即使
__FILE__
中没有分隔符“/”,它也能有效地工作。您可以根据需要将其替换为 \ 来使用它。
使用下面的strrchr源代码改进了strfnchr源代码。我认为它会比 strrchr 更有效。
https://code.woboq.org/userspace/glibc/string/ strrchr.c.html
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
最上面的答案不够好,因为它不是编译时 const 表达式
这是一个非常简单的解决方案:
它是一个 constexpr,可以在头文件中使用。
The top answer is not good enough for it's not a compile-time const expression
Here is a really simple solution:
it's a constexpr and can use in header file.
该解决方案基于 @RenatoUtsch 答案:
CMake list:
C/C++ header
This solution is based on @RenatoUtsch answer:
CMake list:
C/C++ header
对于 Windows,请尝试
使用“\\”而不是“/”。
Try
For Windows use '\\' instead of '/'.
如果您使用 cmake,这里有一个提示。从:
http://public.kitware.com/pipermail/cmake/2013-January /053117.html
我正在复制提示,因此所有内容都在此页面上:
如果您使用 GNU make,我认为您没有理由不能扩展此内容到你自己的 makefile。例如,您可能有这样的行:
其中
$(SOURCE_PREFIX)
是您要删除的前缀。然后使用
__FILENAME__
代替__FILE__
。Here's a tip if you're using cmake. From:
http://public.kitware.com/pipermail/cmake/2013-January/053117.html
I'm copying the tip so it's all on this page:
If you're using GNU make, I see no reason you couldn't extend this to your own makefiles. For example, you might have a line like this:
where
$(SOURCE_PREFIX)
is the prefix that you want to remove.Then use
__FILENAME__
in place of__FILE__
.GCC 8 现在具有
-fmacro-prefix-map
和-ffile-prefix-map
选项:为
-ffile-prefix-map
(-fdebug-prefix-map
) 设置无效路径将中断调试,除非您告诉调试器如何映射回来。 (gdb:设置替换路径
,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__
。GCC 8 now has the
-fmacro-prefix-map
and-ffile-prefix-map
options:Setting an invalid path for
-ffile-prefix-map
(-fdebug-prefix-map
) will break debugging unless you tell your debugger how to map back. (gdb:set substitue-path
, vscode:"sourceFileMap"
).If your intent is to only clean up
__FILE__
just use-fmacro-prefix-map
.Example:
So for my Jenkins builds I will add
-ffile-prefix-map=${WORKSPACE}/=/
, and another to remove the local dev package install prefix.NOTE Unfortunately the
-ffile-prefix-map
and-fmacro-prefix-map
options are only available in GCC 8 onwards. For, say, GCC 5, we only have-fdebug-prefix-map
which does not affect__FILE__
.我刚刚想到了一个很好的解决方案,它可以与源文件和头文件一起使用,非常高效,并且可以在所有平台上的编译时工作,而无需特定于编译器的扩展。此解决方案还保留项目的相对目录结构,因此您知道文件位于哪个文件夹中,并且仅相对于项目的根目录。
这个想法是使用构建工具获取源目录的大小,然后将其添加到 __FILE__ 宏中,完全删除该目录并仅显示从源目录开始的文件名。
以下示例是使用 CMake 实现的,但它没有理由不能与任何其他构建工具一起使用,因为技巧非常简单。
在 CMakeLists.txt 文件中,定义一个宏,其中包含 CMake 上项目的路径长度:
在源代码中,定义一个
__FILENAME__
宏,该宏仅将源路径大小添加到__FILE__
宏:然后只需使用这个新宏而不是
__FILE__
宏。这是有效的,因为__FILE__
路径始终以 CMake 源目录的路径开头。通过从 __FILE__ 字符串中删除它,预处理器将负责指定正确的文件名,并且它将全部相对于 CMake 项目的根目录。如果您关心性能,这与使用
__FILE__
一样高效,因为__FILE__
和SOURCE_PATH_SIZE
都是已知的编译时常量,因此它可以被编译器优化掉。唯一会失败的地方是,如果您在生成的文件上使用它,并且它们位于非源构建文件夹中。然后,您可能需要使用
CMAKE_BUILD_DIR
变量而不是CMAKE_SOURCE_DIR
创建另一个宏。I have just thought of a great solution to this that works with both source and header files, is very efficient and works on compile time in all platforms without compiler-specific extensions. This solution also preserves the relative directory structure of your project, so you know in which folder the file is in, and only relative to the root of your project.
The idea is to get the size of the source directory with your build tool and just add it to the
__FILE__
macro, removing the directory entirely and only showing the file name starting at your source directory.The following example is implemented using CMake, but there's no reason it wouldn't work with any other build tools, because the trick is very simple.
On the CMakeLists.txt file, define a macro that has the length of the path to your project on CMake:
On your source code, define a
__FILENAME__
macro that just adds the source path size to the__FILE__
macro:Then just use this new macro instead of the
__FILE__
macro. This works because the__FILE__
path will always start with the path to your CMake source dir. By removing it from the__FILE__
string the preprocessor will take care of specifying the correct file name and it will all be relative to the root of your CMake project.If you care about the performance, this is as efficient as using
__FILE__
, because both__FILE__
andSOURCE_PATH_SIZE
are known compile time constants, so it can be optimized away by the compiler.The only place where this would fail is if you're using this on generated files and they're on a off-source build folder. Then you'll probably have to create another macro using the
CMAKE_BUILD_DIR
variable instead ofCMAKE_SOURCE_DIR
.C++11
msvc2015u3,gcc5.4,clang3.8.0
https://github.com/search?q=repo%3Aandry81%2Ftacklelib%20content%3A%22get_file_name_constexpr_offset%22&type=code
'
代码在以下情况下生成编译时间偏移:
gcc
:至少gcc6.1 +-O1
msvc
:将结果放入 constexpr 变量:clang
:坚持不编译时评估有一个技巧可以强制所有 3 个编译器进行编译时评估,即使在禁用优化的调试配置中:
https://godbolt.org/z/u6s8j3
C++11
msvc2015u3,gcc5.4,clang3.8.0
https://github.com/search?q=repo%3Aandry81%2Ftacklelib%20content%3A%22get_file_name_constexpr_offset%22&type=code
'
Code generates a compile time offset when:
gcc
: at least gcc6.1 +-O1
msvc
: put result into constexpr variable:clang
: insists on not compile time evaluationThere is a trick to force all 3 compilers does compile time evaluation even in the debug configuration with disabled optimization:
https://godbolt.org/z/u6s8j3
至少对于 gcc,
__FILE__
的值是编译器命令行上指定的文件路径。如果像这样编译file.c
:__FILE__
将扩展为"/full/path/to/file.c"
。如果您这样做:那么
__FILE__
将扩展为"file.c"
。这可能实用,也可能不实用。
C 标准不要求这种行为。关于
__FILE__
的全部内容是它扩展为“当前源文件的假定名称(字符串文字)”。另一种方法是使用
#line
指令。它会覆盖当前行号以及源文件名(可选)。如果您想覆盖文件名但保留行号,请使用 __LINE__ 宏。例如,您可以将其添加到
file.c
的顶部附近:唯一的问题是它将指定的行号分配给下面行,并且第一行
#line
的参数必须是数字序列,因此您不能执行诸如确保
#line
指令中的文件名这样 的操作与文件的实际名称相匹配留作练习。至少对于 gcc 来说,这也会影响诊断消息中报告的文件名。
At least for gcc, the value of
__FILE__
is the file path as specified on the compiler's command line. If you compilefile.c
like this:the
__FILE__
will expand to"/full/path/to/file.c"
. If you instead do this:then
__FILE__
will expand to just"file.c"
.This may or may not be practical.
The C standard does not require this behavior. All it says about
__FILE__
is that it expands to "The presumed name of the current source file (a character string literal)".An alternative is to use the
#line
directive. It overrides the current line number, and optionally the source file name. If you want to override the file name but leave the line number alone, use the__LINE__
macro.For example, you can add this near the top of
file.c
:The only problem with this is that it assigns the specified line number to the following line, and the first argument to
#line
has to be a digit-sequence so you can't do something likeEnsuring that the file name in the
#line
directive matches the actual name of the file is left as an exercise.At least for gcc, this will also affect the file name reported in diagnostic messages.
这里纯粹是编译时解决方案。它基于以下事实:字符串文字的
sizeof()
返回其长度+1。请随意将条件运算符级联扩展到项目中的最大合理文件名。路径长度并不重要,只要您检查距离字符串末尾足够远即可。
我将看看是否可以通过宏递归获得一个没有硬编码长度的类似宏...
Purely compile time solution here. It's based on the fact that
sizeof()
of a string literal returns its length+1.Feel free to extend the conditional operator cascade to the maximum sensible file name in the project. Path length doesn't matter, as long as you check far enough from the end of the string.
I'll see if I can get a similar macro with no hard-coded length with macro recursion...
最近的 Clang 编译器有一个
__FILE_NAME__
宏(请参阅此处)。Recent Clang compiler has a
__FILE_NAME__
macro (see here).对于 Visual Studio,您可以使用(未记录/实验性)
/d1trimfile
编译器选项。它采用不区分大小写的前缀参数,并且具有在计算此宏时从 __FILE__ 中删除此前缀的效果。应用
/d1trimfile:"$(SolutionDir)\"
选项可有效地将所有__FILE__
计算更改为相对于解决方案目录:注意:关于
"
之前的尾随\
的说明:For Visual Studio, you can use the (undocumented/experimental)
/d1trimfile
compiler option. It takes a case-insensitive prefix argument and has the effect of stripping this prefix from__FILE__
whenever this macro is evaluated.Applying the
/d1trimfile:"$(SolutionDir)\"
option effectively changes all__FILE__
evaluations to become solution directory relative:NB: Explanation for the trailing
\
right before the"
:多年来我一直使用与 @Patrick 的答案相同的解决方案。
当完整路径包含符号链接时,它有一个小问题。
更好的解决方案。
为什么要使用这个?
-Wno-builtin-macro-redefine
使重新定义__FILE__
宏的编译器警告静音。<块引用>
对于那些不支持此功能的编译器,请参阅下面的稳健方法。
从文件路径中删除项目路径是您的真正要求。您不会愿意浪费时间去查找
header.h
文件、src/foo/header.h
或src/bar/header 在哪里.h
.我们应该删除
cmake
配置文件中的__FILE__
宏。大多数现有代码中都使用该宏。只需重新定义它即可让您自由。
像
gcc
这样的编译器从命令行参数预定义了这个宏。完整路径写入由cmake
生成的makefile
中。需要
CMAKE_*_FLAGS
中的硬代码。在某些较新的版本中,有一些命令可以添加编译器选项或定义,例如
add_definitions()
和add_compile_definitions()
。这些命令将在应用于源文件之前解析 make 函数,例如subst
。这不是我们想要的。-Wno-builtin-macro-redefine
的稳健方法。I have use the same solution with @Patrick 's answer for years.
It has a small issue when the full path contains symbol-link.
Better solution.
Why should use this ?
-Wno-builtin-macro-redefined
to mute the compiler warnings for redefining__FILE__
macro.Strip the project path from the file path is your real requirement. You won't like to waste the time to find out where is a
header.h
file,src/foo/header.h
orsrc/bar/header.h
.We should strip the
__FILE__
macro incmake
config file.This macro is used in most exists codes. Simply redefine it can set you free.
Compilers like
gcc
predefines this macro from the command line arguments. And the full path is written inmakefile
s generated bycmake
.Hard code in
CMAKE_*_FLAGS
is required.There is some commands to add compiler options or definitions in some more recently version, like
add_definitions()
andadd_compile_definitions()
. These commands will parse the make functions likesubst
before apply to source files. That is not we want.Robust way for
-Wno-builtin-macro-redefined
.在VC中,使用
/FC
时,__FILE__
扩展为完整路径,没有/FC
选项__FILE__
扩展文件名。参考: 这里In VC, when using
/FC
,__FILE__
expands to the full path, without the/FC
option__FILE__
expands file name. ref: here此行为已在某些编译器中实现,您可以使用以下方法获取编译文件的基本名称:
__FILE_NAME__
(自 GCC 12)__FILE_NAME__
(自 CLANG 9.0.0 起)This behaviour has been implemented in some compilers, you can get basename of the compiled file by using:
__FILE_NAME__
(since GCC 12)__FILE_NAME__
(since CLANG 9.0.0)以下是 C++14 或更高版本中使用编译时计算的解决方案:
Here is the solution available with C++14 or newer that uses compile-time calculation:
没有编译时方法可以做到这一点。显然,您可以使用 C 运行时在运行时执行此操作,正如其他一些答案所演示的那样,但在编译时,当预处理器启动时,您就不走运了。
There's no compile time way to do this. Obviously you can do it at runtime using the C runtime, as some of the other answers have demonstrated, but at compile time, when the pre-procesor kicks in, you're out of luck.