具有条件扩展的GCC宏?

时间:2014-01-10 00:51:51

标签: c gcc macros

我几乎可以肯定答案是'不'。但我很固执;我真的很想实现这个功能,循环很重要(读取:嵌入式)。

目标:

对于这个嵌入式应用程序,我有一个需要内联的时钟配置序列。到处都是。我想用宏来做这件事。

问题

时钟配置的执行顺序随参数'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

4 个答案:

答案 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();
    {
}

我发现这种方法可以产生更易读的代码,所以我现在正在使用它。虽然我必须说它打破了我的一条黄金法则不将代码引入头文件*

贾斯汀

*围绕'标题代码'有什么最佳做法吗?我记得一个关于我曾经工作过的项目的恐怖故事,其中数百条线存在于头文件中的结构和格式不良。因此,我在这里使用这种静态内联方法存在冲突。想法?