比较 C 宏

Comparing C macros

我有寻址宏(它在微控制器上,所以访问物理地址是可以的)分解为这个(在一长串条件定义、属性等之后):

#define ADDR_A (*18)
#define ADDR_B (*30)
#define ADDR_C (*18)

我想比较它们以便优化编译:

#if ADDR_A==ADDR_C
    return 1;
#else
    return 0;
#endif

但我得到 "error: operator '*' has no left operand",这是有道理的。是否可以比较宏的定义。我有一种预感,我可以将它们以某种方式转换为字符串以进行比较,但我还没有找到一种方法(比如使用 # 作为宏参数)。

不,我不打算在运行时执行此操作,因为我正在计算周期。

您不能比较 #if 中的字符串,因为:

  • 您只能将 #if 与常量表达式一起使用
  • 字符串只能使用循环或函数进行比较
  • 循环不是常量表达式
  • 和:

    Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated. (C11, 6.6P3)

我能想到的最好的办法是将地址和解除引用分成两个不同的宏,例如:

#define ADDR_A (18)
#define ADDR_B (30)
#define ADDR_C (18)
#define GET_A (*ADDR_A)
#define GET_B (*ADDR_B)
#define GET_C (*ADDR_C)

#if ADDR_A == ADDR_B
return 1
#else
return 0
#endif

请注意,检查常量的相等性 "at runtime" 将被几乎任何称职的编译器省略;在 this example 中,编译器只生成 return 1 的等价物,因为它在编译时知道条件的计算结果为 false;计算周期在这里是一个转移注意力的问题,因为这些比较将被省略。

此外,就其价值而言,我不确定您是如何使用这些宏的(我无法在脑海中构建它们在语法上有效的示例),但我感觉您的代码如果你只是让你的宏包含地址并且你在你的代码中内联取消引用这些地址,会更容易理解。如果我正在阅读您的代码,我更愿意:

#define ADDR_A (18)
#define ADDR_B (30)
#define ADDR_C (18)

if (ADDR_A == ADDR_B)
    return 1
return 0

只把地址放在宏中,把类型信息分开怎么样?

#define ADDR_A (18)
#define ADDR_B (30)
#define ADDR_C (18)

unsigned uint16_t *A = (uint16_t*)ADDR_A;
unsigned uint16_t *B = (uint16_t*)ADDR_B;
unsigned uint16_t *C = (uint16_t*)ADDR_C;

然后你就可以使用你的测试了。

或者,跳过预处理器,直接在 C:

unsigned uint16_t *const A = (uint16_t*)18;
unsigned uint16_t *const B = (uint16_t*)30;
unsigned uint16_t *const C = (uint16_t*)18;

int f()
{
    if (A == C)
        return 1;
    else
        return 0;
}

除非你有一个非常低质量的编译器,你可以期待它识别A==C作为常量表达式并相应地简化代码。