如何正确使用定义作为其他定义的参数? C ++

时间:2015-10-30 02:12:30

标签: c++ macros

我有以下定义宏:

#define NHID 5
#define NENT 10
#define NOUT 4
#define NWEIS (NENT + 1) * NHID + (NHID + 1) * NOUT

因此,每当编译器找到" NWEIS"时,它将替换" NEWIS" for"(NENT + 1)* NHID +(NHID + 1)* NOUT"。但这不是我想要的。我希望它取代" NWEIS"通过实际值= 79,无需在内存中声明额外的变量。有没有一个像样的方法呢?

3 个答案:

答案 0 :(得分:3)

宏替换主要是 1 一个迭代过程。

在宏替换之后你会得到什么一个带有常量的表达式。任何体面的编译器都可以折叠这些常量(在编译时评估它们),以便为您提供79的单个值。

例如,考虑一下程序:

#define NHID 5
#define NENT 10
#define NOUT 4
#define NWEIS (NENT + 1) * NHID + (NHID + 1) * NOUT
int main (void) { return NWEIS; }

这是gcc -E的预处理器输出:

int main (void) { return (10 + 1) * 5 + (5 + 1) * 4; }

这里是它用gcc -S生成的相关汇编代码行(返回值放在eax寄存器中):

movl   $79, %eax

话虽如此,由于你有不断的“变量”,对编译器的内联建议,枚举类型等等,所以使用宏的原因很少,因为宏过去非常有用。

当然,我仍然发现自己正在寻找快速代码的宏,但这主要是因为我是一个古老的鳕鱼,在我们甚至有原型之前的C天就已经伪造了: - )

重新考虑使用它们可能是值得的,因为你可以用以下内容替换它:

const int nhid  =  5;
const int nent  = 10;
const int nout  =  4;
const int nweis = (nent + 1) * nhid + (nhid + 1) * nout;

智能编译器应仍然能够在编译时优化计算,并且您很可能会发现调试器中的变量可用于您,这通常不会发生与宏。

1 完整的详细信息可以在C ++ 11标准的16.3 Macro replacement部分找到。

可以说宏中有###的某些用法会阻止进一步替换 令牌(前者用字符串字符替换令牌)后者将多个令牌组合成不同的令牌。)

由于你没有使用它们,所以这里无关紧要。

答案 1 :(得分:2)

您使用的宏不会花费额外的内存。你已经实现了你想要的东西。

让我们看一下合理的编译器会做什么。

假设您有此代码。

#define NHID 5
#define NENT 10
#define NOUT 4
#define NWEIS (NENT + 1) * NHID + (NHID + 1) * NOUT

int f()
{
    return NWEIS;
}

合理的编译器显然会将其扩展为:

int f()
{
    return (NENT + 1) * NHID + (NHID + 1) * NOUT;
}

下一步将是:

int f()
{
    return (10 + 1) * 5 + (5 + 1) * 4;
}

由于此算术表达式仅由硬编码数字(常量表达式)组成,因此编译器也可将整个事物视为常量。

int f()
{
    return 79;
}

请注意,此函数非常小,合理的编译器会尽力使函数内联。

然而,这样做更为可取:

constexpr int NHID = 5;
constexpr int NENT = 10;
constexpr int NOUT = 4;
constexpr int NWEIS = (NENT + 1) * NHID + (NHID + 1) * NOUT;

答案 2 :(得分:1)

只需使用

const int NHID = 5;
const int NENT 10;
const int NOUT 4;
const int NWEIS = (NENT + 1) * NHID + (NHID + 1) * NOUT;

一个优秀的优化器将在编译时替换这些值,而不是将任何变量放在内存中,除非你做了一些事情,比如取其地址。然后你就得到了C ++的类型安全和范围,没有宏观的恶意。

(大写字母名称按照惯例为宏保留,因此您可能需要稍微重命名)