Path removal prefix
When doing some logging work, you want to get the current file name, not the verbose file path. Path acquisition is often optimized with the underlying functions of each OS. Preprocessing macros are defined in the C++/C standard to help us get file paths. We want to be able to do this at compile time rather than run time to avoid additional performance costs. At the same time, some cross-platform solutions are expected. Here are some ideas:
Method 1: Remove prefixes at runtime
__FILE__ can get an absolute path at compile time, __BASE_NAME__ can get a relative path, but it is not cross-platform. We tried to solve this problem with compile time, but have not yet found a supported compile option. It seems that path cutting can only be done at run time.
- through
__FILE__
Paths are obtained during preprocessing. - define
inline
Functions or macros handle paths.strchr
Is a helpful function, namely, instr
findch
The pointer.
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
Copy the code
Method 2: Compiler function optimization
Replace STRCHR with __builtin_strrchr. The GNU toolchain provides some common compiler optimization functions that can be called at compile time. This allows path switching to be converted to compile time processing. Disadvantages: specific compiler support is required, GNU needs to check whether its own compiler supports it, or check the documentation for GNU versions.
#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
Copy the code
Approach 3: Handle it in the build script
Define the preprocessor macro __FILENAME__ in the compile script, use the shell to remove the file name after the path, and copy the file name to the __FILENAME__ macro at compile time.
- Build the script using cmake
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
Copy the code
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='"$(notdir $<)"'")
Copy the code
- Change in the makefile
CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"
Copy the code
Tips: When defining ___FILENAME__ preprocessor macros, you may want to turn on the -wno-builtin-macro-redefined compilation option.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
Copy the code
Method 4.0: Use CONSTEXPr at compile time
C++11 only allows return statements in constexpr functions. C++14 removes this restriction.
- C + + 11 version
constexpr const char* str_end(const char* str) {
return *str ? str_end(str + 1) : str;
}
constexpr bool str_slant(const char* str) {
return *str == '/' ? true : (*str ? str_slant(str + 1) : false);
}
constexpr const char* r_slant(const char* str) {
return *str == '/' ? (str + 1) : r_slant(str - 1);
}
constexpr const char* file_name(const char* str) {
return str_slant(str) ? r_slant(str_end(str)) : str;
}
Copy the code
- C + + 14 version
constexpr const char* file_name(const char* path) {
const char* file = path;
while (*path) {
if (*path++ == '/') {
file = path;
}
}
return file;
}
Copy the code
- A magic macro
Defining constexpr functions:
using cstr = const char * const;
static constexpr cstr past_last_slash(cstr str, cstr last_slash)
{
return
*str == '\0' ? last_slash :
*str == '/' ? past_last_slash(str + 1, str + 1) :
past_last_slash(str + 1, last_slash);
}
static constexpr cstr past_last_slash(cstr str)
{
return past_last_slash(str, str);
}
Copy the code
Then define a convenient macro method
#define __SHORT_FILE__ ({constexpr cstr sf__ {past_last_slash(__FILE__)}; sf__; })Copy the code
Method 4.1: Verify what is done at compile time
Compile the source code
source file name is foo/foo1/foo2/foo3/foo4.cpp useg++ -o foo.exe foo/foo1/foo2/foo3/foo4.cpp -std=c++11 --save-temps to compile this file.Copy the code
Look at the assembly code after decompiling
.file "foo4.cpp"
.section .rodata
.LC0:
.string "foo/foo1/foo2/foo3/foo4.cpp"
.text
.globl main
.type main, @function
main:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq $.LC0+19, -8(%rbp)
movl $.LC0+19, %edi
call puts
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE4:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
Copy the code
Movl $.LC0+19, % EDI. LC0 + 19 is the address with the path prefix removed.