【问题标题】:Macro questions宏观问题
【发布时间】:2009-04-02 13:27:23
【问题描述】:

在一个软件项目(一些旧的 C 编译器)中,我们有很多变量必须正常保存和反转。

有人知道如何制作这样的宏吗?

SET(SomeVariable, 137);

哪个会执行

SomeVariable = 137;
SomeVariable_inverse = ~137;

编辑:

最好的解决方案似乎是:

#define SET(var,value) do { var = (value); var##_inverse = ~(value); } while(0)

感谢您的回答

【问题讨论】:

  • 如果你想表明这是最好的解决方案,你应该选择那个作为“接受”的解决方案;为贡献它的用户提供声誉奖励,并将其标记为解决您的问题的解决方案。
  • 宏是否也应该在进行赋值之前确保 var = ~var_inverse ?做 { 断言(var == ~var##_inverse); var = (值); var##_inverse = ~(value); } 而 (0)。如果你在任何地方都使用这个宏,这是你最好的检查机会。

标签: c macros


【解决方案1】:

【讨论】:

  • 是否有一篇文章解释了为什么在 do 循环之外使用宏构造?我很好奇为什么...
  • 简而言之:do..while 包装让宏作为一个整体表现为一个语句,这很好。想想 if/else、大括号等等。
  • 一般的想法是你想要一个像函数调用一样工作的宏,这意味着你可以写像“SET(a, 1);”这样的东西。或“如果 (foo) SET(a, 1); 否则 SET(a, 2);”。详情请见c-faq.com/cpp/multistmt.html
  • @Tom,我添加了一些链接,详细说明了为什么这是多语句宏的良好做法。
  • @dmckee,错过了那个(添加)。
【解决方案2】:

我没有看到提到的一个危险是“值”宏参数在大多数解决方案中都会被计算两次。如果有人尝试这样的事情,这可能会导致问题:

int x = 10;
SET(myVariable, x++);

在此调用之后,myVariable 将是 10,而 myVariable_inverse 将是 ~11。哎呀。对 JaredPar 的解决方案稍作改动即可解决此问题:

#define SET(var,value) do { var = (value); var##_inverse = ~(var); } while(0)

【讨论】:

    【解决方案3】:

    既然倒数很容易计算,为什么还要存储它?这对我来说似乎是个坏主意。

    【讨论】:

    • 这是一个安全措施。每个重要的变量都必须以正态和逆向存储。每秒都会检查变量。如果他们错了,就输了。
    • 在具有强烈核辐射的环境中可能有意义。但我很害怕在这样的环境中开发嵌入式软件的开发人员不得不在这里提出这样的问题。
    • 嵌入式软件开发也有初学者。
    • @nuriaion - 在这种情况下,您需要使更新和检查原子化(使用互斥锁或其他东西),因此如果在设置值和设置之间发生检查,所有地狱都不会松动值的“镜像”。
    【解决方案4】:

    您可以在单个语句中执行此操作,从而避免使用 do {} while (0)

    #define SetInverse(token, value) (token##_inverse = ~(token = (value)))
    

    此外,这只会评估一次 (value),这总是很好。

    【讨论】:

    • >> 此外,这只评估(值)一次,这总是很好
    • 稍作修改使此宏返回 (value) 的值,就像它是一个赋值一样(只是在较大的表达式本身中使用它的可能性很小,如果可能不寻常,这是有效的): #define SetInverse(token, value) (token = ~(token##_inverse = ~(value)))
    • 我很想在定义中添加(void) 强制转换,以确保它不能用于更大的表达式,但是是的,让它评估为value 非常容易。
    【解决方案5】:
    #define SetInverse(token, value) { token = value; token##_inverse = ~value; }
    

    Jinx,Jared - 就像你的 while (0) 一样

    【讨论】:

    • 与普通分号 SetInverse(a, 48); 一起使用时会变得有点傻。最终在代码中创建了一个空语句,这(对我来说)比 do..while(0) 循环丑得多。
    • 我想知道字符串化是否有用,但我从来没有在愤怒中使用它,我看不出它在这里如何使用。文档说 ## 防止标识符替换 - 它真的在连续字符串的中间工作吗?
    • 唉,do{}while(0) 是必要的:如果写成 if (1) SetInverse(t, 0); else {printf("unmatched 'else'!\n");},这将失败
    【解决方案6】:

    只是提供一种替代方法:

    将每个变量存储为如下结构:

    typedef struct
    {
        u32 u32Normal;
        u32 u32Inverted;
    } SafeU32TYPE
    

    然后有一个函数,它接受一个指向其中之一的指针,以及要设置的值,并存储该值及其逆:

    void Set(SafeU32TYPE *pSafeU32, u32Data)
    {
        if(pSafeU32 != NULL)
        {
            pSafeU32->u32Normal = u32Data;
            pSageU32->u32Inverted = ~u32Data;
        } /* if */
    } /* Set() */
    

    优点:如果你需要set函数做一些更强大的事情,比如边界检查,或者以某种更复杂的方式存储,那么它可以很容易地扩展。

    缺点:您需要为所使用的每种类型使用不同的函数,如果处理器资源是一个问题,那么这比使用宏效率低。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 2013-07-29
      • 1970-01-01
      相关资源
      最近更新 更多