mah*_*ood 152 c macros file path
C中可用的标准预定义MACRO __FILE__显示文件的完整路径.有没有办法缩短路径?我的意思是代替
/full/path/to/file.c
Run Code Online (Sandbox Code Playgroud)
我知道了
to/file.c
Run Code Online (Sandbox Code Playgroud)
要么
file.c
Run Code Online (Sandbox Code Playgroud)
red*_*ynx 154
尝试
#include <string.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
Run Code Online (Sandbox Code Playgroud)
对于Windows,使用'\\'而不是'/'.
Pat*_*ick 52
如果你正在使用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 $<))\"'")
Run Code Online (Sandbox Code Playgroud)
如果你正在使用GNU make,我认为没有理由你不能将它扩展到你自己的makefile.例如,您可能有这样一行:
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"
Run Code Online (Sandbox Code Playgroud)
$(SOURCE_PREFIX)
您要删除的前缀在哪里.
然后用来__FILENAME__
代替__FILE__
.
Ren*_*sch 21
我刚刚想到了一个适用于源文件和头文件的优秀解决方案,非常高效,并且可以在所有平台上编译时无需编译器特定的扩展.此解决方案还保留项目的相对目录结构,因此您知道文件所在的文件夹,并且只知道项目的根目录.
我们的想法是使用您的构建工具获取源目录的大小,然后将其添加到__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}")
Run Code Online (Sandbox Code Playgroud)
在源代码中,定义一个__FILENAME__
宏,只是将源路径大小添加到__FILE__
宏:
#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)
Run Code Online (Sandbox Code Playgroud)
然后只使用这个新宏而不是__FILE__
宏.这是有效的,因为__FILE__
路径始终以CMake源目录的路径开头.通过从__FILE__
字符串中删除它,预处理器将负责指定正确的文件名,它将全部相对于CMake项目的根目录.
如果你关心的表现,这是因为使用高效__FILE__
,因为无论__FILE__
与SOURCE_PATH_SIZE
已知的编译时间常数,因此它可以被编译器优化掉.
唯一会失败的地方是你在生成的文件上使用它并且它们位于一个非源的构建文件夹中.那么你可能不得不使用CMAKE_BUILD_DIR
变量来创建另一个宏而不是CMAKE_SOURCE_DIR
.
Sev*_*yev 16
在这里纯粹编译时间解决方案.它基于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__)
Run Code Online (Sandbox Code Playgroud)
随意将条件运算符级联扩展到项目中的最大敏感文件名.路径长度无关紧要,只要您从字符串末尾检查足够远即可.
我会看看是否可以获得一个类似的宏,没有硬编码长度的宏递归...
And*_*dry 15
msvc2015u3,gcc5.4,clang3.8.0
template <typename T, size_t S>
inline constexpr size_t get_file_name_offset(const T (& str)[S], size_t i = S - 1)
{
return (str[i] == '/' || str[i] == '\\') ? i + 1 : (i > 0 ? get_file_name_offset(str, i - 1) : 0);
}
template <typename T>
inline constexpr size_t get_file_name_offset(T (& str)[1])
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
'
int main()
{
printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
}
Run Code Online (Sandbox Code Playgroud)在以下情况下,代码会生成编译时间偏移:
gcc
: 至少 gcc6.1 + -O1
msvc
:将结果放入 constexpr 变量:
constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
printf("%s\n", file);
Run Code Online (Sandbox Code Playgroud)clang
: 坚持不编译时评估
即使在禁用优化的调试配置中,也有一个技巧可以强制所有 3 个编译器进行编译时评估:
namespace utility {
template <typename T, T v>
struct const_expr_value
{
static constexpr const T value = v;
};
}
#define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value
int main()
{
printf("%s\n", &__FILE__[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(__FILE__))]);
}
Run Code Online (Sandbox Code Playgroud)
Kei*_*son 11
至少对于gcc,值__FILE__
是编译器命令行中指定的文件路径.如果您这样编译file.c
:
gcc -c /full/path/to/file.c
Run Code Online (Sandbox Code Playgroud)
在__FILE__
将扩大到"/full/path/to/file.c"
.如果你这样做:
cd /full/path/to
gcc -c file.c
Run Code Online (Sandbox Code Playgroud)
然后__FILE__
将扩展到公正"file.c"
.
这可能是也可能不实际.
C标准不要求这种行为.所有它说的__FILE__
是它扩展为"当前源文件的假定名称(字符串文字)".
另一种方法是使用该#line
指令.它会覆盖当前行号,也可以覆盖源文件名.如果要覆盖文件名但仅保留行号,请使用__LINE__
宏.
例如,您可以在顶部附近添加file.c
:
#line __LINE__ "file.c"
Run Code Online (Sandbox Code Playgroud)
唯一的问题是它将指定的行号分配给下一行,并且第一个参数#line
必须是一个数字序列,所以你不能做类似的事情
#line (__LINE__-1) "file.c" // This is invalid
Run Code Online (Sandbox Code Playgroud)
确保#line
指令中的文件名与文件的实际名称相匹配,这是一个练习.
至少对于gcc,这也会影响诊断消息中报告的文件名.
对于 Visual Studio,您可以使用该/d1trimfile
选项。
您可能想将其设置为/d1trimfile:"$(SolutionDir)\"
:
注意:\
对 之前尾随的解释"
:
要转义第一个(
$(SolutionDir)
以反斜杠结尾),否则引号将被转义。引用前需要均匀数量的反斜杠。
此行为已在某些编译器中实现,您可以使用以下方法获取编译文件的基本名称:
__FILE_NAME__
(自GCC 12起)__FILE_NAME__
(自CLANG 9.0.0起)以下是 C++14 或更高版本中使用编译时计算的解决方案:
constexpr auto* getFileName(const char* const path)
{
const auto* startPosition = path;
for (const auto* currentCharacter = path;*currentCharacter != '\0'; ++currentCharacter)
{
if (*currentCharacter == '\\' || *currentCharacter == '/')
{
startPosition = currentCharacter;
}
}
if (startPosition != path)
{
++startPosition;
}
return startPosition;
}
std::cout << getFileName(__FILE__);
Run Code Online (Sandbox Code Playgroud)
晚会晚了一点,但是对于海湾合作委员会,请看看以下-ffile-prefix-map=old=new
选项:
编译位于old目录中的文件时,请在编译结果中记录对它们的所有引用,就好像这些文件位于new目录中一样。指定此选项等效于指定所有单个
-f*-prefix-map
选项。这可用于制作与位置无关的可复制构建。另请参阅-fmacro-prefix-map
和-fdebug-prefix-map
。
因此,对于我的Jenkins构建,我将添加-ffile-prefix-map=${WORKSPACE}/=/
,另一个将删除本地dev软件包的安装前缀。
注意不幸的是,该-ffile-prefix-map
选项仅在GCC 8及更高版本中可用-fmacro-prefix-map
,我认为正是这一点__FILE__
。例如,对于GCC 5,我们只有-fdebug-prefix-map
(不会)影响__FILE__
。
多年来,我对@Patrick 的回答使用了相同的解决方案。
当完整路径包含符号链接时,它有一个小问题。
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
Run Code Online (Sandbox Code Playgroud)
-Wno-builtin-macro-redefined
使重新定义__FILE__
宏的编译器警告静音。
对于那些不支持的编译器,请参考下面的Robust 方式。
从文件路径中剥离项目路径是您真正的要求。您不想浪费时间找出header.h
文件src/foo/header.h
或src/bar/header.h
.
我们应该删除配置文件中的__FILE__
宏cmake
。
该宏用于大多数现有代码。只需重新定义它就可以让您自由。
编译器喜欢gcc
从命令行参数预定义这个宏。并且完整路径写在makefile
s 生成的 s 中cmake
。
需要硬编码CMAKE_*_FLAGS
。
有一些命令可以在最近的版本中添加编译器选项或定义,例如add_definitions()
和add_compile_definitions()
。这些命令将像subst
之前一样解析 make 函数应用于源文件。那不是我们想要的。
-Wno-builtin-macro-redefined
。include(CheckCCompilerFlag)
check_c_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
Run Code Online (Sandbox Code Playgroud)
请记住从该
set(*_FLAGS ... -D__FILE__=...)
行中删除此编译器选项。
没有编译时的方法来做到这一点。显然,您可以在运行时使用 C 运行时执行此操作,正如其他一些答案所证明的那样,但是在编译时,当预处理器启动时,您就不走运了。