【问题标题】:C macro function has the same output of equivalent normal function, but the algorithm has a different outputC宏函数与等价普通函数输出相同,但算法输出不同
【发布时间】:2023-03-13 05:05:01
【问题描述】:

所以我有一个与宏函数具有相同定义的函数,它们输出相同的值。为了确认这一点,我这样做了:

int a(int vertex, int offset) {
      int value = vertex*numberOfoffsets + offset;
      if (value != b(vertex, offset)) printf("error\n");
      return value;
}

这是宏:

#define b(vertex, offset) (vertex*numberOfoffsets + offset)  //EDIT: I had mta instead of b here (on the stackoverflow post)

请注意,numberOfOffsets 本身也是一个宏,它返回 6。 我使用a(vertex,offset) 运行算法,一切正常,没有打印error\n,这意味着两个函数返回相同的值。

但是当我使用b(vertex,offset) 而不是a(vertex,offset) 运行算法时,会出现错误的答案(尽管算法不会中断。

关于宏,我有什么遗漏的吗?他们不只是替换文本吗?我真的不明白这种行为。

编辑:对不起,我忘了更改函数的名称,b 现在是正确的(它是定义函数)

EDIT2:添加括号可以解决问题,因此应该是:

#define b(vertex, offset) (((vertex)*(numberOfoffsets)) + (offset))

但其他用户建议我改用内联函数,所以现在是:

static __inline__
int b(int vertex, int offset) {
  return vertex*numberOfoffsets + offset;
}

【问题讨论】:

  • 这里的b 是什么?
  • 请显示你所有的代码,b。您从不使用 mta,因此它似乎无关紧要。您是在说“此代码给出了错误的答案”,但不显示代码、输入或答案
  • 通常,您应该在宏定义中使用过多的括号,例如#define mta(v,o,n) ((v)*(n) + (o))
  • 宏不是函数。它仅在编译之前用其他内容替换文本内容。宏不返回任何内容。尽可能避免使用这种宏(几乎总是这样)。如果您想避免函数调用 - 请改用内联函数。宏容易出错并且很难调试
  • 发布numberOfoffsets的定义。

标签: c macros


【解决方案1】:

通常,您应该在宏定义中使用过多的括号,例如

#define b(vertex, offset) ((vertex) * 6 + (offset))

否则,运算符优先级可能会将结果更改为意外的结果。例如,用

调用宏
int x = 4;
int y = b(x+1, 3);

应该与y = 5 * 6 + 3 = 33 相同。但是,如果没有括号,结果是
y = 4 + 1*6 + 3 = 13


@jxh 在 cmets 中指出,宏和函数之间还有另一个区别。

当调用带有int 参数的函数,并且参数不是int 类型时,编译器会将参数隐式转换为int。但使用宏时,不会进行此类转换。

例如代码

#define b(vertex, offset) ((vertex) * 6 + (offset))

int a(int vertex, int offset)
{
    return vertex * 6 + offset;
}

int main(void)
{
    double vertex = 3.3;
    double offset = 7.4;
    int resultA = a(vertex, offset);
    int resultB = b(vertex, offset);
    printf("%d %d\n", resultA, resultB);
}

将打印25 27。这是因为编译器在调用函数之前将vertex 转换为3 并将offset 转换为7。但是宏使用double 值进行数学运算,并通过分配给resultB 将答案转换为int

您是否需要对此做任何事情是有争议的。但是,要使宏与函数完全等价,您可以将其编写为

#define b(vertex, offset) ((int)((int)(vertex) * 6 + (int)(offset)))

【讨论】:

  • @EricPostpischil 否则您的键盘会更快磨损。有太多比缺少一对要好。
  • 这绝对是。我在外面有额外的括号,认为这就足够了,但事实并非如此。现在可以使用了,谢谢!
  • @Myntekt 酷,很高兴我能帮上忙 :)
  • 也有可能函数计算为int,而宏可能以更高的精度计算。
  • @user3386109 我现在明白他的意思了。这不是问题,因为数字总是整数,但它可能是。感谢您的帮助
猜你喜欢
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 2012-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
  • 2013-10-08
相关资源
最近更新 更多