如何在编译时提取没有路径和后缀的源文件名?

新手上路,请多包涵

使用带有 -std=c11 的 gcc 和带有 -std=c++14 的 g++。

例如,对于名为 src/dir/Hello.cxx 的文件,它应该扩展为如下内容:

 const char basename[] = "Hello";

或者

const char basename[] = getStaticBasename(__FILE__);

其中 getStaticBasename() 是一个宏(对于 C 源代码)或 constexpr 函数(对于 C++ 源代码),它会导致“Hello”。

我必须避免在运行时从 __FILE__ 拆分字符串,因为路径和后缀不得以任何方式编译到可执行文件中。

该解决方案必须不依赖于大型库,例如 boost。

由于我没有生成文件,因此在我的情况下不能使用 这样 的解决方案。

有人对此有解决方案吗?

编辑 2015-07-02:

  • 我对编译器和链接器的调用方式没有影响(有时通过makefile,有时从命令行或某些IDE(Eclipse CDT 管理的make、Crossworks、Xcode 等。所以解决方案只需要在代码中。
  • 我的用例是为小型日志记录解决方案提供某种“通用区域标识符”。应用程序代码(使用我的记录器)应该只 #include <Joe/Logger.h> 并且在以后调用例如 LOG_DEBUG(...) 我将隐含地使用自动生成的“通用区域标识符”。
  • 我目前的解决方案是,应用程序代码必须先声明一个 JOE_LOG_FILE_REGION(Hello); (在 #include <Joe/Logger.h> 之后),然后才能在其代码中放置 LOG_DEBUG(...)

原文由 Joe 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 809
1 个回答

1. gcc内置函数可以在编译时获取完整路径的文件名。

#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)

或者

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

2. c++11 constexpr 也可以在编译时做到这一点。

c++11 constexpr 函数只能使用返回语句。

例子:

 #include <stdio.h>

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;
}

int main() {
    constexpr const char *const_file = file_name(__FILE__);
    puts(const_file);
    return 0;
}

源文件名是 foo/foo1/foo2/foo3/foo4.cpp

使用 g++ -o foo.exe foo/foo1/foo2/foo3/foo4.cpp -std=c++11 --save-temps 编译这个文件。

你可以看到这个。

 .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

movl $.LC0+19, %edi .LC0 + 19 是没有路径和后缀的文件名字符串的地址

3. c++14 constexpr 函数可以简单的做到这一点

#include <iostream>

constexpr const char* file_name(const char* path) {
    const char* file = path;
    while (*path) {
        if (*path++ == '/') {
            file = path;
        }
    }
    return file;
}

int main() {
    constexpr const char* file = file_name(__FILE__);
    std::cout << file << std::endl;
    return 0;
}

c++14 constexpr 函数可以使用循环和局部变量。

file_name 函数将在编译时替换为 const char * 的地址。 ~

原文由 pexeer 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题