C语言中可用的标准预定义宏__FILE__显示文件的完整路径。有办法缩短这条路吗?我的意思是

/full/path/to/file.c

我看到

to/file.c

or

file.c

当前回答

red1ynx的答案经过调整,甚至更加“臃肿”:

#define __FILENAME__ \
  (strchr(__FILE__, '\\') \
  ? ((strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)) \
  : ((strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)))

如果我们发现反斜杠,我们就分反斜杠。否则,拆分为正斜杠。很简单。

几乎任何替代方案都会更简洁(在我看来,c++ constexpr确实是这里的黄金标准)。然而,如果你正在使用一些__BASE_FILE__不可用的编译器,这可能是有帮助的。

其他回答

使用basename()函数,或者,如果是在Windows上,使用_splitpath()。

#include <libgen.h>

#define PRINTFILE() { char buf[] = __FILE__; printf("Filename:  %s\n", basename(buf)); }

还可以在shell中尝试man 3 basename。

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__, '/')

如果您最终在本页上寻找一种方法,以从您正在交付的二进制文件中删除指向丑陋构建位置的绝对源路径,那么下面可能适合您的需要。

尽管这并没有得到作者所希望的答案,因为它假设使用CMake,但它已经非常接近了。很遗憾之前没有人提到这一点,因为这可以节省我很多时间。

OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)

将上述变量设置为ON将生成如下格式的构建命令:

cd /ugly/absolute/path/to/project/build/src && 
    gcc <.. other flags ..> -c ../../src/path/to/source.c

因此,__FILE__宏将解析为../../src/path/to/source.c

CMake文档

但是要注意文档页上的警告:

使用相对路径(可能不起作用!)

它不能保证在所有情况下都能工作,但在我的CMake 3.13 + gcc 4.5中工作

最近的Clang编译器有一个__FILE_NAME__宏(见这里)。

我刚刚想到了一个很好的解决方案,它可以同时使用源文件和头文件,非常有效,并且可以在所有平台的编译时工作,没有特定于编译器的扩展。此解决方案还保留了项目的相对目录结构,因此您可以知道文件在哪个文件夹中,并且只相对于项目的根目录。

其思想是用构建工具获取源目录的大小,并将其添加到__FILE__宏中,完全删除目录,只显示从源目录开始的文件名。

下面的例子是使用CMake实现的,但是没有理由它不能与任何其他构建工具一起工作,因为技巧非常简单。

在CMakeLists.txt文件中,定义一个宏,该宏具有到CMake上项目的路径长度:

# 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都是已知的编译时常量,因此可以由编译器优化。

唯一会失败的地方是如果你在生成的文件上使用这个,而且它们在一个off-source build文件夹上。然后,您可能必须使用CMAKE_BUILD_DIR变量而不是CMAKE_SOURCE_DIR创建另一个宏。