多次调用C预处理器宏(通过变量)

时间:2013-05-17 08:51:08

标签: c assembly macros

我想清理我的汇编代码并提供一种通过宏多次调用“NOP”的方法:

#define NOP() asm(" nop")

#define NOP_N( N ) \
    NOP(); \
    NOP(); \
    .... call NOP() N times

我无法确定宏是否可以。

显然,出于性能原因,我不想要这样的东西:

#define NOP_N( n ) { register int i; for(i=0;i<n;i++) asm(" nop"); }

这违背了NOP的目的:

L17:                                    ; NOP_N(3);
        nop
        addi      1,r0                  ; Unsigned
        cmpi      3,r0
        blo       L17

代码在C和汇编中,因此这里不能涉及C ++。此外,编译器相当陈旧,不支持可变参数宏...

3 个答案:

答案 0 :(得分:4)

我认为无限制N的解决方案是可能的。对于有界N,您可以按以下方式执行操作:

#define REPEAT_0(WHAT)
#define REPEAT_1(WHAT) WHAT REPEAT_0(WHAT)
#define REPEAT_2(WHAT) WHAT REPEAT_1(WHAT)
#define REPEAT_3(WHAT) WHAT REPEAT_2(WHAT)

#define NOP_N(N) REPEAT_##N(asm("nop");)

第一部分可以轻松自动生成。第二部分采用的技术有时称为token pasting

答案 1 :(得分:2)

thisIs the C preprocessor Turing complete?

#define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__

AND REPEAT_INDIRECT

#define REPEAT(count, macro, ...) \
    WHEN(count) \
    ( \
        DEFER(REPEAT_INDIRECT) () \
        ( \
            DEC(count), macro, __VA_ARGS__ \
        ) \
        DEFER(macro) \
        ( \
            DEC(count), __VA_ARGS__ \
        ) \
    )
#define REPEAT_INDIRECT() REPEAT

//An example of using this macro
#define M(s, i, _) i
EVAL(REPEAT(8, M, ~)) // 0 1 2 3 4 5 6 7

AND FOREVER:

#define FOREVER() \
    ? \
    DEFER(FOREVER_INDIRECT) () ()
#define FOREVER_INDIRECT() FOREVER
// Outputs question marks forever
EVAL(FOREVER())

答案 2 :(得分:0)

如果您真的想在预处理器中执行此操作(并且具有符合C99的编译器),则可以使用P99中的P99_UNROLL

但是你完全低估了现代编译器能够实现的优化。只要边界是编译时常量,优秀的编译器就应该为您展开代码。查看汇编程序以确定(gcc有-S)。

但你可能通过“正确”编码来帮助编译器:

#define NOP_N(N) for(register unsigned i=0; i < (N); i++) asm(" nop")

也就是说,让循环计数器在for本地,并使用无符号类型,这样就不存在溢出的理论问题。