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

4
我希望能够清理我的汇编代码并提供一个宏的方式来多次调用“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 ++。同时,编译器比较老旧,不支持变参宏...


如何将其编写为宏以便于“N”,“调用NOP() N次”,其中N必须在编码时知道。 - Grijesh Chauhan
1
@Mogria:如果xgbi可以使用C ++,那么可以通过模板元编程相当简单地完成此操作,而不需要任何预处理技巧。 - jamesdlin
可能是重复问题:https://dev59.com/RGbWa4cB1Zd3GeqPUjxa - krlmlr
相关链接:https://dev59.com/F3RC5IYBdhLWcg3wXP0C - krlmlr
代码是用C和汇编语言编写的,因此这里不能涉及C++。此外,编译器相当老旧,不支持可变参数宏... - Gui13
3个回答

7
我认为无界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");)

第一部分可以很容易地自动生成。用于第二部分的技术有时被称为令牌粘贴

那是我预见到的最接近的可能性,而不需要可变参数宏。 - Gui13

2

那么关于这个C预处理器是否是图灵完备的?怎么样呢?

#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

永远:

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

1
能否详细说明一下这段代码的作用?否则,将链接放在评论中虽然很好,但不适合作为答案。 - krlmlr

0

如果你真的想在预处理器中这样做(并且有符合C99标准的编译器),你可以使用P99中的P99_UNROLL

但是你完全低估了现代编译器所能实现的优化。只要边界是编译时常量,一个好的优化编译器应该会为你展开代码。查看汇编以确保(gcc有-S)。

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

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

那就是,将循环计数器设为本地变量,并使用无符号类型,以避免理论上的溢出问题。

问题在于编译器确实*有点老了。我检查过,使用for循环将会初始化整数而不是展开循环。 - Gui13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接