4

我有一个问题:我想使用abs库的功能complex

但是,我遇到错误警告我abs使用的功能是#define abs(x) (x > 0) ? x : -(x).

因此,我认为问题来自我的进口。因为我还包含了 stdio 和 stdlib 库,所以编译器可以使用abs这些库之一中定义的函数。

所以我的问题是:如何在不删除任何导入的情况下使用abs库的功能?complex

非常感谢您的回复。

4

4 回答 4

15

用括号包裹它。

(abs)(whatever);

这将强制编译器使用函数版本,因为宏不再匹配。

类似函数的宏通过匹配标识符后跟左括号来工作(。由于我们将函数名称本身包装在括号中,因此我们有一个标识符后跟一个右括号),它无法匹配宏。括号在语义上是透明的,但它们抑制了宏语法。

IIRC,是splintC 检查器教给我的。在编写 postscript 解释器时,我创建了很好的短宏来访问堆栈。

#define push(o) (*tos++ = (o))
#define pop() (*--tos)

在它们成为表达式的一部分的棘手部分之前,这很棒tos。为了避免未定义的行为,我必须创建函数版本并将其用于那些棘手的地方。对于新设计,我完全跳过了宏。


编辑:我有一种挥之不去的感觉,实际上是我在 Coelocanthe 书(Peter Van Der Linden 的Deep C Secrets)中学到了这一点,上述情况是我第一次需要它的地方。IIRC 他的示例涉及putchargetchar通常作为符合 C 实现的函数和宏来实现。

于 2013-04-25T07:07:39.477 回答
6

采用#undef

#include "header1.h"
#include "header2.h"
#undef abs // remove abs macro

x = std::abs(y);
于 2013-04-25T07:09:10.653 回答
4

虽然上面的几个建议非常好,但我会采取完全不同的角度。几乎可以肯定,类似windows.h的事情会导致abs(). 您应该不能在执行复杂数学运算的文件中包含“windows.h”[至少在大多数类型的程序中](我不知道 Windows 中有一个函数complex<T>作为参数,所以我'很确定你不需要在同一个源文件中同时使用“complex.h”和“windows.h”。这种方法称为“隔离系统依赖项”,这样做是一件非常好的事情。

查看您的代码,找到您实际使用 Windows 函数的位置,然后仅在实际需要它的文件中包含“windows.h”。如果您使用 Visual Studio,您可能会发现“windows.h”作为“stdafx.h”的一部分包含在内,这意味着所有有趣的宏等都包含在所有地方,因为“stdafx .h" 包含在所有源文件中。

于 2013-04-25T07:43:16.280 回答
1

和括号解决方案都#undef可以工作,但我建议有一些更强大的东西,因为这两种解决方案都需要你每次想要调用时都这样做abs,下次你可能会忘记并导致错误。

你可以做什么:

  1. 将您的函数名称更改为不太常见的名称 :absolutemyAbs...
  2. 将您的函数\类放在名称空间下(对于 C++ 而不是 C),那么调用是显式的myNameSpace::abs(x)
  3. 如果它不能像这里的评论建议的那样工作,我仍然会在我的函数中扭曲调用:

    键入 myAbs(类型参数){ 返回(绝对值)(参数);}

于 2013-04-25T07:16:47.357 回答