从__FILE__编译时修剪路径和扩展名



----问题----

我正试图将文件名"/路径/to/Module.cpp";转换成保持值"0"的CCD_ 1;模块";编译时。这有助于我在微控制器中打印符合人体工程学的日志。我使用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__);

这导致CCD_ 2保持"0";模块.cpp";。这是一个好的开始,但我想去掉";。cpp";也编译时间,自然。有什么想法吗?

----答案----

多亏了@KamilCuk,我能够想出以下头文件,当它包含在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] {'', };
};
/// 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("%sn", TAG.str());
}

相关内容

最新更新