我有以下定义宏:
#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++的类型安全性和作用域,而没有了宏的邪恶。
(按照惯例,大写名称是为宏保留的,因此您可能需要稍微重命名它们)