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

/full/path/to/file.c

我看到

to/file.c

or

file.c

当前回答

纯粹的编译时解决方案。它基于这样一个事实:字符串字面量的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__)

请随意将条件操作符级联扩展到项目中最大的合理文件名。路径长度并不重要,只要检查距离字符串的末尾足够远。

我将看看我是否可以得到一个类似的宏,没有硬编码的长度与宏递归…

其他回答

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__。

编译时没有办法做到这一点。显然,您可以在运行时使用C运行时实现它,正如其他一些答案所演示的那样,但是在编译时,当预处理器启动时,您就不走运了。

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

其思想是用构建工具获取源目录的大小,并将其添加到__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创建另一个宏。

这个解决方案是基于@RenatoUtsch的答案:

CMake列表:

string(LENGTH "${PROJECT_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
add_definitions("-DSOURCE_PATH=\"${PROJECT_SOURCE_DIR}\"")

C / C + + header

#define __FILENAME__ strstr(__FILE__, SOURCE_PATH) + SOURCE_PATH_SIZE