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



我有以下定义宏:

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

因此,每当编译器找到"NWEIS"时,它都会将"NEWIS"替换为"(NENT+1)*NHID+(NHID+1)*NOUT"。但那不是我想要的。我希望它用实际值=79替换"NWEIS",而不必在内存中声明额外的变量。有什么像样的方法吗?

宏替换主要是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节中找到。

只要说###在宏中的某些用途可以防止令牌的进一步替换(前者用字符串文字替换令牌,后者将多个令牌组合成不同的标记)。

既然你没有使用这些,这里就无关紧要了。

您使用的宏不会占用额外的内存。你已经得到了你想要的。

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

假设您有这个代码。

#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;

只需使用

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

一个好的优化器将在编译时替换这些值,并且不会在内存中放置任何变量,除非您执行诸如获取它们的地址之类的操作。然后你就有了C++的类型安全性和作用域,而没有了宏的邪恶。

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

最新更新