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

下面是一个解决方案,适用于没有字符串库的环境(Linux内核,嵌入式系统等):

#define FILENAME ({ \
    const char* filename_start = __FILE__; \
    const char* filename = filename_start; \
    while(*filename != '\0') \
        filename++; \
    while((filename != filename_start) && (*(filename - 1) != '/')) \
        filename--; \
    filename; })

现在只需使用FILENAME而不是__FILENAME__。是的,它仍然是一个运行时的东西,但它是有效的。

如果你使用CMAKE和GNU编译器,这个全局定义工作正常:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")

上面的答案不够好,因为它不是一个编译时const表达式 这里有一个非常简单的解决方案:

 #define FILESTEM(x)                                                        \
  std::string_view(x).substr(std::string_view(x).rfind(OS_PATH_SLASH) + 1, \
                             std::string_view(x).rfind('.') -              \
                                 std::string_view(x).rfind(OS_PATH_SLASH) - 1)

它是一个constexpr,可以在头文件中使用。

#include <algorithm>
#include <string>
using namespace std;
string f( __FILE__ );
f = string( (find(f.rbegin(), f.rend(), '/')+1).base() + 1, f.end() );

// searches for the '/' from the back, transfers the reverse iterator 
// into a forward iterator and constructs a new sting with both