__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_DIR
variables而不是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 $<))\"'")