简体   繁体   English

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

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

I was working on a small application that I'm building a simple CLI for. 我正在开发一个用于为其构建简单CLI的小型应用程序。 I wanted my CLI to have some colors because who likes boring old white and black consoles?? 我希望CLI具有一些颜色,因为谁喜欢无聊的旧白色和黑色控制台? (jk no offense if you do:)) (如果您这样做,则无罪:)

Then as I was building onto it I seem to have run into a problem that I, unfortunately, don't understand :(. The problem lies in some borrowed code that is supposed to help me clean the code by wrapping all the necessary code into neat little functions or definitions (you'll see what I'm talking about soon). I don't really know how definitions work in C++ or at least the more advanced ones but here is the code I currently have for wrapping the CLI color code functions into: 然后,当我在其上进行构建时,我似乎遇到了一个不幸的是我不理解的问题:(。问题在于某些借用的代码可以通过将所有必要的代码包装到其中来帮助我清理代码简洁的小函数或定义(您很快就会看到我在说什么)。我真的不知道定义在C ++或至少更高级的定义中是如何工作的,但这是我目前用于包装CLI颜色的代码代码功能分为:

Colors.h 颜色.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_ */

So the problem is that this below works: 因此,问题在于以下方法有效:

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

and this doesn't... 这不是...

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

Again, I'm not too familiar with how "defined functions" work but I was just wondering if anybody could possibly show me a new method that accepts both the raw text input and a variable input to the defined functions. 同样,我对“定义的函数”的工作方式不太熟悉,但是我只是想知道是否有人可以向我展示一种既接受原始文本输入又接受对定义的函数进行变量输入的新方法。 Also if you could help me understand how definitions work more in C++ that would be awesome as well. 另外,如果您可以帮助我理解定义在C ++中的工作方式,那么也很棒。

Macros work the same way as if you copy-pasted the macro definition to the place where it's used. 宏的工作方式与将宏定义复制粘贴到使用的位置相同。

So this works: 所以这工作:

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++ has a rule whereby adjacent string literals get joined together. I imagine this rule was added so that you can do exactly what you're doing here) (C ++有一条规则,可以将相邻的字符串文字连接在一起。我想像是添加了此规则,以便您可以完全按照此处的操作进行操作)

And this doesn't work: 这不起作用:

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

You are concatenating strings with macros, macros are not functions. 您正在将字符串与宏连接起来,宏不是函数。 You can't invoke macros with variables. 您不能使用变量调用宏。 For example the following program will print "hello world" 例如,以下程序将打印“ hello world”

#include <iostream>

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

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

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

So when you "invoke" the macro, after preprocessing your code looks like this 因此,当您“调用”宏时,预处理后的代码如下所示

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

You are essentially combining the arguments to the macro together before compilation at preprocessing time. 本质上,您是在预处理时进行编译之前,将宏的参数组合在一起。 So with variables in your example you get the following 因此,在示例中使用变量,您将获得以下内容

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

Which is ill formed C++, since you can't concatenate non string literals with string literals like that. 这是格式错误的C ++,因为您无法将非字符串文字与这样的字符串文字连接在一起。


Remember that macros do nothing but plain text replacement. 请记住,宏只能执行纯文本替换。

The difference is because FBLU is a preprocessor macro (and NOT a function) that works as you expect ONLY if its parameter is a string literal. 区别在于, FBLU是一个预处理器宏(而不是一个函数),仅当其参数为字符串文字FBLU可以按预期工作。 The preprocessor does TEXT substitution to produce source code - which is passed to a later phase of compilation. 预处理器执行TEXT替换以生成源代码-将其传递到编译的后续阶段。

The preprocessor will turn 预处理器将打开

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

into 进入

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

which (by substituting the macros KBLU and RST ) becomes (通过替换宏KBLURST )变为

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

which is a set of string literals, which get appended (again by the preprocessor) to become a single string literal 这是一组字符串文字,它们被附加(再次由预处理器添加)成为单个字符串文字

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

The net effect is that 最终结果是

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

is seen by the compiler as 被编译器视为

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

which is a perfectly valid code statement. 这是一个完全有效的代码语句。

This doesn't work for 这不适用于

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

since 以来

FBLU(randomString)

is preprocessed to become 经过预处理成为

KBLU randomString RST 

which (by substituting the macros KBLU and RST ) becomes (通过替换宏KBLURST )变为

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

Now, since randomString is an identifier (name of a variable, in this case), the preprocessor does no further macro substitution, and 现在,由于randomString是标识符(在这种情况下为变量的名称),因此预处理器不再进行宏替换,并且

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

is seen by the compiler as 被编译器视为

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

which is not a valid statement. 这不是有效的声明。

The difference (depending on whether the argument to FBLU() is a string literal or a variable) is one of many reasons that usage of macros is actively discouraged in C++. 这种差异(取决于FBLU()的参数是字符串文字还是变量)是在C ++中积极禁止使用宏的众多原因之一。

There are various alternatives that can be used instead, but the essential guideline is "Don't use macros". 可以使用多种替代方法,但是基本准则是“不要使用宏”。

For example, change the header files to convert the macros with no arguments into variable declarations, such as 例如,更改头文件以将不带参数的宏转换为变量声明,例如

#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

and the macros with arguments into inline functions 以及带有内联函数参数的宏

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

After doing this, both of your examples will work as expected. 完成此操作后,您的两个示例都将按预期工作。

The compilation of a C++ program involves three steps: preprocessing, compilation, linking. C ++程序的编译涉及三个步骤:预处理,编译,链接。

So, you see, preprocessing goes first. 因此,您会看到,预处理首先进行。 At that time content of variable is not known to preprocessor, so your second code snippet unrolls to the following: 那时,预处理器不知道变量的内容,因此您的第二个代码片段将展开至以下内容:

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

which produces syntax error. 产生语法错误。

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

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