簡體   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