__FILE__macros显示完整path

C中可用的标准预定义MACRO __FILE__显示文件的完整path。 有什么方法可以缩短path吗? 我的意思是,而不是

/full/path/to/file.c 

我懂了

 to/file.c 

要么

 file.c 

尝试

 #include <string.h> #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) 

对于Windows使用'\\'而不是'/'。

这里有一个提示,如果你使用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 $<))\"'") 

如果你使用GNU make,我看不出有什么理由不能把它扩展到你自己的makefile。 例如,你可能有这样一行:

 CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'" 

其中$(SOURCE_PREFIX)是您要删除的前缀。

然后使用__FILENAME__代替__FILE__

没有编译时间的方法来做到这一点。 显然你可以在运行时使用C运行库来做到这一点,正如其他一些答案所certificate的那样,但是在编译时,当预处理程序启动时,你运气不好。

至less对于gcc, __FILE__的值是编译器命令行中指定的文件path。 如果你像这样编译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__是它扩展为“当前源文件(string文字)的假定名称”。

另一种方法是使用#line指令。 它会覆盖当前的行号,也可能会覆盖源文件的名称。 如果您想覆盖文件名,但保留行号,请使用__LINE__macros。

例如,你可以在file.c的顶部附近添加它:

 #line __LINE__ "file.c" 

确保#line指令中的文件名与文件的实际名称相匹配。

至less对于gcc来说,这也会影响诊断消息中报告的文件名。

@ red1ynx提出的一个细微的变化就是创build下面的macros:

 #define SET_THIS_FILE_NAME() \ static const char* const THIS_FILE_NAME = \ strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__; 

在每个.c(pp)文件中添加:

 SET_THIS_FILE_NAME(); 

那么你可以参考THIS_FILE_NAME而不是__FILE__

 printf("%s\n", THIS_FILE_NAME); 

这意味着每个.c(pp)文件执行一次构造,而不是每次引用macros时。

它仅限于使用.c(pp)文件,并且不能从头文件中使用。

既然你使用GCC,你可以利用

__BASE_FILE__该macros以Cstring常量的forms扩展为主input文件的名称。 这是在预处理器或C编译器的命令行中指定的源文件

然后通过在编译时更改源文件表示(完整path/相对path/基本名称)来控制如何显示文件名。

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

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

也可以在shell中尝试man 3 basename

我做了一个macros__FILENAME__ ,避免每次切割完整的path。 问题是将结果文件名保存在cpp-localvariables中。

通过在.h文件中定义一个静态全局variables可以轻松完成。 该定义在包含.h的每个.cpp文件中给出单独的和独立的variables。 为了成为一个multithreading的certificate,值得使这个variables也是线程本地的(TLS)。

一个variables存储文件名(缩小)。 另一个是__FILE__给出的非削减值。 h文件:

 static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL; static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL; 

macros本身用所有的逻辑调用方法:

 #define __FILENAME__ \ GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName) 

而function是这样实现的:

 const char* GetSourceFileName(const char* strFilePath, const char*& rstrFilePathHolder, const char*& rstrFileNameHolder) { if(strFilePath != rstrFilePathHolder) { // // This if works in 2 cases: // - when first time called in the cpp (ordinary case) or // - when the macro __FILENAME__ is used in both h and cpp files // and so the method is consequentially called // once with strFilePath == "UserPath/HeaderFileThatUsesMyMACRO.h" and // once with strFilePath == "UserPath/CPPFileThatUsesMyMACRO.cpp" // rstrFileNameHolder = removePath(strFilePath); rstrFilePathHolder = strFilePath; } return rstrFileNameHolder; } 

removePath()可以用不同的方式实现,但是快速和简单似乎是strrchr:

 const char* removePath(const char* path) { const char* pDelimeter = strrchr (path, '\\'); if (pDelimeter) path = pDelimeter+1; pDelimeter = strrchr (path, '/'); if (pDelimeter) path = pDelimeter+1; return path; } 

这里纯粹编译时间的解决scheme。 它基于string的sizeof()返回其长度+ 1的事实。

 #define STRIPPATH(s)\ (sizeof(s) > 11 && (s)[sizeof(s)-12] == '/' ? (s) + sizeof(s) - 11 : \ sizeof(s) > 10 && (s)[sizeof(s)-11] == '/' ? (s) + sizeof(s) - 10 : \ sizeof(s) > 9 && (s)[sizeof(s)-10] == '/' ? (s) + sizeof(s) - 9 : \ sizeof(s) > 8 && (s)[sizeof(s)-9] == '/' ? (s) + sizeof(s) - 8 : \ sizeof(s) > 7 && (s)[sizeof(s)-8] == '/' ? (s) + sizeof(s) - 7 : \ sizeof(s) > 6 && (s)[sizeof(s)-7] == '/' ? (s) + sizeof(s) - 6 : \ sizeof(s) > 5 && (s)[sizeof(s)-6] == '/' ? (s) + sizeof(s) - 5 : \ sizeof(s) > 4 && (s)[sizeof(s)-5] == '/' ? (s) + sizeof(s) - 4 : \ sizeof(s) > 3 && (s)[sizeof(s)-4] == '/' ? (s) + sizeof(s) - 3 : \ sizeof(s) > 2 && (s)[sizeof(s)-3] == '/' ? (s) + sizeof(s) - 2 : (s)) #define __JUSTFILE__ STRIPPATH(__FILE__) 

随意将条件运算符级联扩展到项目中最大的敏感文件名称。 path长度并不重要,只要你从string的末尾检查足够的距离。

我会看看如果我可以得到一个类似的macros,没有macrosrecursion的硬编码的长度…

我刚才想到了一个很好的解决scheme,可以同时处理源文件和头文件,非常高效,可以在所有平台上的编译时工作,而无需编译器特定的扩展。 该解决scheme还保留了项目的相对目录结构,因此您知道文件在哪个文件夹中,并且只相对于项目的根目录。

这个想法是用你的构build工具来获取源代码目录的大小,并将其添加到__FILE__macros,完全删除目录,只显示源文件目录中的文件名。

下面的例子是使用CMake实现的,但没有理由不能使用其他的构build工具,因为这个技巧非常简单。

在CMakeLists.txt文件中,定义一个具有CMake项目path长度的macros:

 # 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__macros,它将源path大小添加到__FILE__macros:

 #define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE) 

然后使用这个新的macros而不是__FILE__macros。 这是有效的,因为__FILE__path将始终以您的CMake源目录的path开始。 通过将其从__FILE__string中移除,预处理器将负责指定正确的文件名,它将全部相对于您的CMake项目的根。

如果你关心性能,这和使用__FILE__一样高效,因为__FILE__SOURCE_PATH_SIZE都是已知的编译时间常量,所以它可以被编译器优化掉。

这将失败的唯一的地方是,如果你在生成的文件上使用它,他们在一个非源代码构build文件夹。 那么你可能需要使用CMAKE_BUILD_DIRvariables而不是CMAKE_SOURCE_DIR来创build另一个macros。

只是希望提高一下FILEmacros:

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

这和Czarek Tomczak所要求的一样,并且在我的混合环境中工作很好。

尝试

 #pragma push_macro("__FILE__") #define __FILE__ "foobar.c" 

在你的源文件中joininclude语句后添加

 #pragma pop_macro("__FILE__") 

在源文件的末尾。

在vs中,当使用/ FC时, FILE等于完整path,没有/ FC FILE等于文件名。 在这里参考

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

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