繁体   English   中英

#defined函数只能接受原始输入,不能接受变量?

[英]#defined functions can only accept raw input not variables?

我正在开发一个用于为其构建简单CLI的小型应用程序。 我希望CLI具有一些颜色,因为谁喜欢无聊的旧白色和黑色控制台? (如果您这样做,则无罪:)

然后,当我在其上进行构建时,我似乎遇到了一个不幸的是我不理解的问题:(。问题在于某些借用的代码可以通过将所有必要的代码包装到其中来帮助我清理代码简洁的小函数或定义(您很快就会看到我在说什么)。我真的不知道定义在C ++或至少更高级的定义中是如何工作的,但这是我目前用于包装CLI颜色的代码代码功能分为:

颜色.h

#ifndef _COLORS_
#define _COLORS_

/* FOREGROUND */
#define RST  "\x1B[0m"   // RESET
#define KRED  "\x1B[31m" // RED
#define KGRN  "\x1B[32m" // GREEN
#define KYEL  "\x1B[33m" // YELLOW
#define KBLU  "\x1B[34m" // BLUE
#define KMAG  "\x1B[35m" // MAGENTA
#define KCYN  "\x1B[36m" // CYAN
#define KWHT  "\x1B[37m" // WHITE

#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST

#define BOLD(x) "\x1B[1m" x RST // BOLD
#define UNDL(x) "\x1B[4m" x RST // UNDERLINE


#endif  /* _COLORS_ */

因此,问题在于以下方法有效:

std::cout << FBLU("Hello, World. I'm blue!") << std::endl;

这不是...

std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;

同样,我对“定义的函数”的工作方式不太熟悉,但是我只是想知道是否有人可以向我展示一种既接受原始文本输入又接受对定义的函数进行变量输入的新方法。 另外,如果您可以帮助我理解定义在C ++中的工作方式,那么也很棒。

宏的工作方式与将宏定义复制粘贴到使用的位置相同。

所以这工作:

std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
// same as
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;
// same as
std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;

(C ++有一条规则,可以将相邻的字符串文字连接在一起。我想像是添加了此规则,以便您可以完全按照此处的操作进行操作)

这不起作用:

std::string randomString = "Hello, World. I'm blue!";

std::cout << FBLU(randomString) << std::endl;
// same as
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;
// oops, syntax error

您正在将字符串与宏连接起来,宏不是函数。 您不能使用变量调用宏。 例如,以下程序将打印“ hello world”

#include <iostream>

using std::cout;
using std::endl;

int main() {
    cout << "hello " "world" << endl;
}

参见https://wandbox.org/permlink/EbG5ZUgVfKLo9lEq

因此,当您“调用”宏时,预处理后的代码如下所示

std::cout << FBLU("Hello, World. I'm blue!") << std::endl;
std::cout << "\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m" << std::endl;

本质上,您是在预处理时进行编译之前,将宏的参数组合在一起。 因此,在示例中使用变量,您将获得以下内容

std::cout << FBLU(randomString) << std::endl;
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;

这是格式错误的C ++,因为您无法将非字符串文字与这样的字符串文字连接在一起。


请记住,宏只能执行纯文本替换。

区别在于, FBLU是一个预处理器宏(而不是一个函数),仅当其参数为字符串文字FBLU可以按预期工作。 预处理器执行TEXT替换以生成源代码-将其传递到编译的后续阶段。

预处理器将打开

FBLU("Hello, World. I'm blue!")

进入

KBLU "Hello, World. I'm blue!" RST 

(通过替换宏KBLURST )变为

"\x1B[34m" "Hello, World. I'm blue!" "\x1B[0m"

这是一组字符串文字,它们被附加(再次由预处理器添加)成为单个字符串文字

"\x1B[34mHello, World. I'm blue!\x1B[0m"

最终结果是

std::cout << FBLU("Hello, World. I'm blue!") << std::endl;

被编译器视为

std::cout << "\x1B[34mHello, World. I'm blue!\x1B[0m" << std::endl;

这是一个完全有效的代码语句。

这不适用于

std::string randomString = "Hello, World. I'm blue!";
std::cout << FBLU(randomString) << std::endl;

以来

FBLU(randomString)

经过预处理成为

KBLU randomString RST 

(通过替换宏KBLURST )变为

"\x1B[34m" randomString "\x1B[0m"

现在,由于randomString是标识符(在这种情况下为变量的名称),因此预处理器不再进行宏替换,并且

std::cout << FBLU(randomString) << std::endl;

被编译器视为

std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;

这不是有效的声明。

这种差异(取决于FBLU()的参数是字符串文字还是变量)是在C ++中积极禁止使用宏的众多原因之一。

可以使用多种替代方法,但是基本准则是“不要使用宏”。

例如,更改头文件以将不带参数的宏转换为变量声明,例如

#include <string>   // needed in the header since we're using std::string

/* FOREGROUND */
const std::string RST = "\x1B[0m";   // RESET
const std::string KRED = "\x1B[31m"; // RED

 // etc

以及带有内联函数参数的宏

inline std::string FRED(const std::string &x)
{
    return KRED + x + RST;
}

完成此操作后,您的两个示例都将按预期工作。

C ++程序的编译涉及三个步骤:预处理,编译,链接。

因此,您会看到,预处理首先进行。 那时,预处理器不知道变量的内容,因此您的第二个代码片段将展开至以下内容:

std::string randomString = "Hello, World. I'm blue!";
std::cout << "\x1B[34m" randomString "\x1B[0m" << std::endl;

产生语法错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM