如何在传递给 C/C++ 宏之前解析 int 变量?

How to resolve int variable before passing to C/C++ Macros?

本文关键字:int 变量 C++      更新时间:2023-10-16

我正在尝试执行以下代码:

#define channel1 10
#define channel(id) channel##id
int main(){
int id = 1;
cout << channel(id)<<"n";
return 0;
}

我收到以下错误:error: use of undeclared identifier 'channelid'

相反,我希望输出为 10,因为channel(id)应该预处理为channel1,并将值替换为10

有什么办法可以实现吗?

导致此问题的原因是您尝试混合在代码处理的不同阶段考虑的信息。

宏和所有 CPP(C 预处理器(的东西(顾名思义(先于其他任何事情发生。它对变量值一无所知(最多是关于 #define(,它所做的大部分工作都是文本争吵。

一些变量值可能在编译时是已知的(见constexpr(...但其中大多数只能在运行时知道。

因此,总而言之,您的代码失败是因为预处理器对id变量一无所知。

编辑:解释总和示例。

我们有这个代码x.cpp

#define sum(a,b) a + b
int main(int argc, char **argv) {
int x = 1, y = 2;
return sum(x,y);    
}

并且此代码可以编译并正常工作。

让我们看看幕后发生了什么。

所有 C/C++ 源文件都经过预处理。这意味着它们使用与 C 或 C++ 不同的语言进行评估:CPP(C 预处理器(。这个CPP是所有#...东西(例如搜索和包含头文件(,正如我所说,与 C 或 C++ 无关。

实际上,您甚至可以在没有编译器的情况下运行它(尝试cpp x.cpp(,或者您可以指示编译器仅执行此阶段(g++ -o x.i -E x.cpp(

如果我们研究 x.i:

# 1 "x.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "x.cpp"

int main(int argc, char **argv) {
int x = 1, y = 2;
return x + y;
}

我们可以观察到几件事:

  1. 还有许多额外的"#"行。编译器使用这些来跟踪所有内容的来源以及所包含位的来源,以便能够提供有意义的错误消息。
  2. 请注意代码中如何替换我们的 sum 宏。这是盲目的,结果发现字符串是不正确的 C/C++ 语法,它不会被检测到,但只有在完成实际的 C/C++ 解析时才会被检测到。

解决方案很简单,不要这样做

宏不能处理呈现在几分钟、几小时、几天、几年(可能是几十年后(的值。宏在编译之前解析,并且在编译之前无法知道id包含什么值。在编译期间有点,但即便如此,它也会变得复杂,除非初始化器是微不足道的并且变量的值永远不会改变。

相反,请使用一个函数:

#include <iostream>
#include <stdexcept>
int channel(const int id)
{
// Your own rules here; we don't know enough about them to know.
// Perhaps instead of a switch, a map. It depends.
switch (id)
{
case 1:  return 10;
default: throw std::out_of_range("Dammit");
}
}
int main()
{
int id = 1;
std::cout << channel(id) << 'n';
}

同样,如果在编译时已知id,则可以使其在编译时工作,并使用关键字constexpr表示:

#include <iostream>
#include <stdexcept>
template <int id>
int channel()
{
// Perhaps instead of a switch, a sequence of 'if constexpr' and
// a static_assert(false) at the end.
switch (id)
{
case 1:  return 10;
default: throw std::out_of_range("Rats");
}
}
int main()
{
constexpr int id = 1;
std::cout << channel<id>() << 'n';
}

如果这两种方法都不可接受的,则必须重新制定您的要求。

但是,在不知道这些要求实际是什么的情况下,我们无法帮助您做到这一点。

你需要另一层间接寻址,并且id是一个宏,而不是一个变量(它不能与变量一起使用 - 宏在令牌级别工作;它们不能知道C变量的值,只能知道预处理器宏的值(。

以下修改后的代码有效(即打印 10(:

#include <iostream>
using namespace std;
#define channel1 10
#define channel_(id) channel##id
#define channel(id) channel_(id)
#define id 1
int main(){
cout << channel(id)<<"n"; 
return 0;
}