我几乎可以肯定答案是'不'。但我很固执;我真的很想实现这个功能,循环很重要(读取:嵌入式)。
目标:
对于这个嵌入式应用程序,我有一个需要内联的时钟配置序列。到处都是。我想用宏来做这件事。
问题
时钟配置的执行顺序随参数'f'(新时钟频率)而变化。
- if (f>10) do A first
- if (f<=10) do A last
- f is a compile time constant.
示例
#define setup_post10(f) doA(f); \
doB(f); \
doC(f)
#define setup_pre10(f) doB(f); \
doC(f); \
doA(f)
问题
如何通过简单的设置(f)封装它?例如。我想:
#define set(f) #if(f>10) \
setup_post10(f) \
#else \
setup_pre10(f) \
#end
但在宏定义中使用预处理程序指令(例如#if)是无效的(据我理解)。
有办法做到这一点吗?对于我的应用,每个周期(和闪存的字节)都很珍贵;我很固执我想在我的代码中使用这种抽象级别。
谢谢!
-Justin
答案 0 :(得分:5)
如果每个周期都很珍贵,那么你应该在装配中进行编码。 :)
如果您信任C编译器优化器,那么就这样做
#define set(f) if((f)>10) setup_post10(f) \
else setup_pre10(f)
如果f
是常量,那么编译器将只选择其中一个条件分支进行编译,假设您启用了最小的优化。例如,set(11)
应直接转换为对setup_post10(11)
答案 1 :(得分:4)
签出Boost预处理器库(http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/index.html)。它包括一种执行此类操作的方法 - 特别是它具有BOOST_PP_LESS
。
虽然如果你只是针对特定的编译器,但是使用函数而不是宏可能更容易,并强制它内联。然后,您可以使用简单的if
,并依赖优化器来优化它以获得常量参数。更新的GCC版本甚至可以断言某些值是编译器时间常量,我认为,这几乎可以保证if
永远不会实际发出。
答案 2 :(得分:0)
如果您对GCC以外的编译器不具备可移植性,可以使用GCC的'statement expression'扩展来处理这个问题:
#define setup_post10(f) ({ doA(f); doB(f); doC(f); 0; })
#define setup_pre10(f) ({ doB(f); doC(f); doA(f); 0; })
#define set(f) (((f) <= 10) ? setup_pre10(f) : setup_post10(f))
如果在条件运算符的控制表达式中测试的表达式是编译时常量,则编译器将仅为将要执行的表达式发出代码,并且删除将永远不会执行的分支的代码(可能不在-O0
优化级别。)
答案 3 :(得分:0)
我还发现在头文件中使用静态内联函数可以获得相同的结果。
示例强>
static inline set(uint8_t f) {
if(f > 10) {
doA();
doB();
doC();
} else {
doB();
doC();
doA();
{
}
我发现这种方法可以产生更易读的代码,所以我现在正在使用它。虽然我必须说它打破了我的一条黄金法则不将代码引入头文件* !
贾斯汀
*围绕'标题代码'有什么最佳做法吗?我记得一个关于我曾经工作过的项目的恐怖故事,其中数百条线存在于头文件中的结构和格式不良。因此,我在这里使用这种静态内联方法存在冲突。想法?