簡體   English   中英

從 __FILE__ 編譯時修剪路徑和擴展名

[英]Trim both path and extension from __FILE__ compile-time

- - 問題 - -

我正在嘗試將文件名“/path/to/Module.cpp”轉換為包含值“Module”編譯時間的const char* 這有助於我在微控制器中打印符合人體工程學的日志。 我使用 GCC 8.3。

有很多關於如何僅剝離路徑組件的好例子,例如這個答案的改編

constexpr const char* filename(std::string_view path) {
    return path.substr(path.find_last_of('/') + 1).data();
}

static const char* TAG = filename(__FILE__);

這導致TAG持有“Module.cpp”。 這是一個好的開始,但我也想去掉“.cpp”。 編譯時,自然。 有任何想法嗎?

- - 回答 - -

感謝@KamilCuk,我能夠提出以下 header 文件,當包含在 cpp 文件中時,它為 ESP IDF 日志記錄宏創建了一個很好的標簽:

#ifndef _LOG_HPP_
#define _LOG_HPP_

#include "esp_log.h"
#include <string_view>

// Note: path processing naïvely assumes a valid Unix file path containing
// directories and an extension.

/**
 * Find the length of stem in a file name
 * @param path A file name with '/' as path separator and '.' as extension separator
 * @return Number of characters in file stem excluding terminating zero
 */
constexpr size_t stemNameLen(const std::string_view& path) {
    return path.find_last_of('.') - path.find_last_of('/') - 1;
}

// Rudimentary unit test
static_assert(stemNameLen(std::string_view("../foo/bar/MyModule.cpp")) == 8);

/**
 * Get the stem in a file name
 * @param path A file name with '/' as path separator and '.' as extension separator
 * @return A string_view holding the stem of the input file name
 */
constexpr std::string_view stemName(const std::string_view& path) {
    return path.substr(path.find_last_of('/') + 1, stemNameLen(path));
}

// Rudimentary unit test
static_assert(stemName(std::string_view("../foo/bar/MyModule.cpp")) == "MyModule");

/// Helper class for creating a C-style zero-terminated string from a string_view
template <size_t N>
class TerminatedString {
public:
    constexpr TerminatedString(const std::string_view& path) {
        size_t i = 0;
        for (auto it = path.cbegin(); i + 1 < sizeof(_str) && it != path.cend(); i++, it++) {
            _str[i] = *it;
        }
    }
    constexpr const char *str() const {
        return _str;
    }
private:
    char _str[N] {'\0', };
};

/// Module name from the file which includes this header
static constexpr std::string_view moduleName = stemName(__BASE_FILE__);
/// A zero-terminated log prefix from module name, initialized compile-time
static constexpr TerminatedString<moduleName.length() + 1> logPrefix{moduleName};

// Sanity check, assumes all file stems in project are less than 100 chars
static_assert(moduleName.length() < 100);

#define err(args...) ESP_LOGE(logPrefix.str(), args)
#define warn(args...) ESP_LOGW(logPrefix.str(), args)
#define info(args...) ESP_LOGI(logPrefix.str(), args)
#define debug(args...) ESP_LOGD(logPrefix.str(), args)
#define trace(args...) ESP_LOGV(logPrefix.str(), args)

#endif // _LOG_HPP_

以下“有效”,但並不完全干凈。 清理它是一項練習。 無論如何,它可能會告訴你如何做到這一點:

#include <cstdio>

constexpr unsigned long filename_we_size(const char *path) {
    // I know - some C pointer stuff. I don't know which C++ functions are 
    // constexpr which are not, and I am too lazy to check, so I used C pointers. 
    // Preferably rewrite it in more C++-ish style.
    auto i = path;
    while (*i) ++i;
    auto end = i;
    while (*i != '.' && i != path) --i;
    const auto ext_len = end - i;
    while (*i != '/' && i != path) --i;
    const auto filename_len = end - i;
    return filename_len - ext_len;
}

constexpr const char *filename_we(const char *path, char *out) {
    auto i = path;
    while (*i) ++i;
    while (*i != '/' && i != path) --i;
    if (*i) ++i;
    auto r = out;
    while (*i != '.' && *i) *r++ = *i++;
    *r = 0;
    return r;
}

// A structure. *Something* has to store the memory.
template <size_t N>
struct Tag {
    char mem[N]{};
    constexpr Tag(const char *path) {
        filename_we(path, mem);
    }
    constexpr const char *str() const {
        return mem;
    }
    constexpr operator const char *() const{
        return mem;
    }    
    constexpr char operator[](size_t i) const {
        return mem[i];
    }
};

static constexpr Tag<filename_we_size(__FILE__)> TAG{__FILE__};

int main() {
    printf("%s\n", TAG.str());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM