【问题标题】:Is there any difference between this two macros? [duplicate]这两个宏有什么区别吗? [复制]
【发布时间】:2019-11-15 14:12:44
【问题描述】:

我发现这两个宏之间没有区别,除了第一个宏周围的括号。

是可读性问题还是处理运算符优先级的一种方式?

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*a))
#define TAM_ARRAY2(a) sizeof(a)/sizeof(*a)

【问题讨论】:

  • is it a way to deal with the priority of operators 是的。一个简单的例子是宏#define sum(a,b) a + b,它在代码sum(1, 2) * 3 中将被翻译成1 + (2 * 3),这不是大多数人所期望的。

标签: c c-preprocessor


【解决方案1】:

是的,有区别。括号是必需的,以便宏的结果被评估为单个表达式,而不是与使用宏的周围上下文混合。

这个程序的输出:

#include <stdio.h>

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*a))
#define TAM_ARRAY2(a) sizeof(a)/sizeof(*a)

int main(void)
{
    int x[4];
    printf("%zu\n", 13 % TAM_ARRAY (x));
    printf("%zu\n", 13 % TAM_ARRAY2(x));
}

是,在 C 实现中,int 是四个字节:

1 3

因为:

  • 13 % TAM_ARRAY (x)13 % (sizeof(x)/sizeof(*x)) 替换,后者分组为 13 % (sizeof(x) / sizeof(*x)),计算结果为 13 % (16 / 4),然后是 13 % 4,然后是 1
  • 13 % TAM_ARRAY2(x)13 % sizeof(x)/sizeof(*x) 替换,后者分组为 (13 % sizeof(x)) / sizeof(*x),计算结果为 (13 % 16) / 4,然后是 13 / 4,然后是 3

按照这些思路,TAM_ARRAY 最好在 a 的第二个实例周围也包含括号:

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*(a)))

【讨论】:

  • 你的反例比我的更贴切:)
  • @chqrlie:谢谢。它实际上可能会在实践中出现,因为有时使用键以包装方式插入数组,因此索引计算为键模数组大小的余数。我只是去了 C 标准并寻找少数会证明问题的运算符。
  • 确实很好。你有sizeof(*a) 的非人为例子吗?
  • @chqrlie:我什么也没看到。该参数必须包含一个优先级低于一元 * 的运算符,但是,当任何此类运算符的操作数是一个数组时,它将被转换为一个指针,因此 TAM_ARRAY 无论如何都无法实现其目的。
【解决方案2】:

在代码翻译的早期阶段,宏被替换为文本。除非特别预料到副作用,否则在宏扩展和宏扩展本身(如果它是表达式)中将宏参数完全括起来非常重要。

在发布的案例中,您不太可能遇到问题,因为很少有运算符具有更高的优先级,并且它们可能不会用于宏扩展,但这是一个病态的示例:

  • TAM_ARRAY(a)["abcd"] 扩展为 (sizeof(a)/sizeof(*a))["abcd"]
  • TAM_ARRAY2(a)["abcd"] 扩展为 sizeof(a)/sizeof(*a)["abcd"],相当于 sizeof(a) / (sizeof(*a)["abcd"])

但是请注意,在宏扩展之前放置具有相同优先级的运算符(例如 %)肯定会导致问题,如 Eric Postpischil 的回答中所述。

还要注意a 也应该用括号括起来:

#define TAM_ARRAY(a) (sizeof(a) / sizeof(*(a)))

【讨论】:

    【解决方案3】:

    宏的工作方式是在编译时“换出”代码。 所以像

    #define ADD(i, j) i + j
    int k = ADD(1, 2) * 3 
    

    将被视为:int k = 1 + (2 * 3)

    然而,

    #define ADD(i, j) (i + j)
    int k = ADD(1, 2) * 3
    

    将被视为:int k = (1 + 2) * 3

    因此,由于运算符优先级,可能有两个宏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-08
      • 2012-03-21
      • 2011-01-14
      • 2013-12-17
      • 2013-02-19
      • 2020-07-22
      相关资源
      最近更新 更多