如何用#define获取无扩展名文件名并存储到PROGMEM中
解决方案
方案1:用构建系统(比如Makefile)生成编译时常量
这是最靠谱、完全没运行时开销的法子——直接通过构建脚本提前处理好文件名,把它定义成编译宏:
操作步骤:
- 在Makefile里加这段代码(假设你的源文件变量是
SOURCE_FILE):# 提取不带路径和扩展名的文件名 MODULE_NAME := $(basename $(notdir $(SOURCE_FILE))) # 把它变成编译时可用的宏 CFLAGS += -DMODULE_NAME="\"$(MODULE_NAME)\"" - 然后在C代码里直接用这个宏定义PROGMEM常量:
#include <avr/pgmspace.h> const char PROGMEM module_name[] = MODULE_NAME;
这种方法全程在编译前就把文件名处理完了,最终生成的常量直接存在PROGMEM里,程序跑起来根本不用额外做任何操作,内存和性能开销为零。
方案2:靠GCC编译器扩展实现编译时字符串截取
如果没法改构建系统,那就利用GCC的编译时优化特性,直接在代码里写宏——编译器会自动把它优化成常量:
#include <avr/pgmspace.h> #include <string.h> // 先拿到不带路径的文件名 #define __FILENAME_NO_PATH__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // 编译时直接截掉扩展名 #define __FILENAME_NO_EXT__ \ (__extension__ ({ \ const char *base = __FILENAME_NO_PATH__; \ const char *dot = strrchr(base, '.'); \ // 算好目标字符串长度,生成编译时常量数组 const size_t len = dot ? (size_t)(dot - base) : strlen(base); \ char buf[len + 1]; \ strncpy(buf, base, len); \ buf[len] = '\0'; \ buf; \ })) // 存到PROGMEM里 const char PROGMEM module_name[] = __FILENAME_NO_EXT__;
GCC能识别__FILE__是字符串字面量,会把strrchr和strlen的计算提前到编译时完成,最终直接生成不含路径和扩展名的字符串常量存入PROGMEM,运行时啥额外操作都不用做。
注意:这个方案依赖GCC的扩展特性,只适用于AVR GCC、ARM GCC这类支持该特性的编译器。
方案3:纯预处理器递归宏(有长度限制)
如果必须用纯预处理器实现(不依赖编译器的运行时优化),可以试试递归宏处理字符串,但要注意——文件名不能太长,得在预处理器的递归上限以内(默认一般是200左右):
#include <avr/pgmspace.h> // 递归宏:逐个字符扫,碰到'.'或者'\0'就停 #define _STRIP_EXT_CHARS(s, i) \ (s[i] == '.' || s[i] == '\0' ? '\0' : (s[i], _STRIP_EXT_CHARS(s, i+1))) // 先拿不带路径的文件名 #define __FILENAME_NO_PATH__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // 生成无扩展名的字符串 #define __FILENAME_NO_EXT__ (const char[]){ _STRIP_EXT_CHARS(__FILENAME_NO_PATH__, 0) } const char PROGMEM module_name[] = __FILENAME_NO_EXT__;
这个方案完全靠预处理器展开生成字符串,但文件名太长的话会触发编译错误,适合短文件名的场景。
内容的提问来源于stack exchange,提问作者N_A
相关产品推荐
相关产品推荐

