使用变量替代 #define 宏定义

4

Libcurl使用以下内容来定义电子邮件收件人:

#define RECIPIENT "<bla@bla.com>"

如果我不想硬编码收件人怎么办?我希望用户能够提供自己的电子邮件地址,所以我需要找到一种方法来实现:

std::string emailreceiver = "bla@bla.com";
#define RECIPIENT = emailreceiver

这行代码中使用了“recipient”:

rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);

我假设我不能简单地将其更改为:
std::string emailreceiver = "bla@bla.com";
rcpt_list = curl_slist_append(rcpt_list, emailreceiver);

有人有什么建议吗?

这与IT技术无关。

@DavidSchwartz 因为它看起来太好了,但实际上并不是那么好 ;) + 我仍然很好奇是否可以将变量分配给 #define。 - natli
在宏定义中,你不希望出现=; - Keith Thompson
3个回答

9

Curl需要一个C字符串(const char *),而不是C++字符串(std::string)。因此,请尝试:

std::string emailreceiver = "bla@bla.com";
rcpt_list = curl_slist_append(rcpt_list, emailreceiver.c_str());

不需要使用#define,那只是一个例子。

回家后我会测试一下。只是出于好奇,是否有可能将变量分配给 #define?你知道的,以防我想要懒惰模式 ;) - natli
不,不是的 - #define 是在预处理阶段被替换掉的。 - Adrian Cornish
3
#define是在编译过程中被展开的宏定义。如果你尝试这样做:#define RECEIPT email_receiver,那么无论你在哪里使用RECEIPT,它都会被展开成文本email_receiver。这可能有效,但前提是email_receiver的类型适用于那个地方。 - Jerry Coffin
1
如果你的代码已经散布了RECIPIENT,那么你可以使用#define RECIPIENT emailreceiver.c_str()(没有分号!)来进行定义。 - Klas Lindbäck

4

您的最后一段代码可能已经很接近了。从外观上看,curl 似乎期望一个 C 风格的字符串,因此您 可能需要 将其更改为:

std::string emailreceiver = "bla@bla.com";
rcpt_list = curl_slist_append(rcpt_list, emailreceiver.c_str());

2
libcurl并不真正做到这一点。您问题中的#define最接近于docs/examples/smtp-multi.c中的一行:
#define RECIPIENT "<recipient@example.com>"

该宏仅在同一源文件中使用一次:
rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);

“引用的行来自curl版本7.23.0。”
“正如文件名所示,这只是一个例子。在真正的应用程序中,您不太可能想要使用硬编码的宏作为收件人姓名。”
“在curl.h中,curl_slist_append的声明为:”
CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
                                                 const char *);

“不用担心现在的CURL_EXTERN或const。”
“当您调用curl_slist_append时,第二个参数必须是char*类型。特别地,它可以是字符串字面值,直接写在调用中或由宏扩展导致的。但只要它指向有效的字符串,它可以是任何char*类型的表达式。”
“您需要决定如何确定收件人电子邮件地址,并将指向该字符串的指针(C风格字符串,而不是C++的std::string)作为第二个参数传递给curl_slist_append。可能没有意义使用宏来实现这个目的。这只是示例程序演示正在发生的事情的简单方法。”
关于你在评论中提出的问题:“我仍然好奇是否可以将变量分配给#define。”——嗯,是和不是。你不能将任何东西“分配”给一个#define。一个#define(宏定义)是一个编译时构造,它会导致任何宏名称的出现都被替换为宏定义的文本文字。例如,这样:
#define RECIPIENT "<recipient@example.com>"
rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);

这句话的意思是:“确切地等同于这个:”。
rcpt_list = curl_slist_append(rcpt_list, "<recipient@example.com>");

除了后者不定义“RECIPIENT”以外(except that the latter doesn't leave RECIPIENT defined)。如果您将宏定义从"<recipient@example.com>"更改为任何你喜欢的其他内容,那么每次出现RECIPIENT都将被替换为您在#define RECIPIENT之后编写的内容。
所以你可以做这样一个事情:
char *recipient = get_recipient();
#define RECIPIENT recipient
rcpt_list = curl_slist_append(rcpt_list, RECIPIENT);

但其实没有意义;你可以直接写:
rcpt_list = curl_slist_append(rcpt_list, recipient);

预处理器(编译器处理#define指令和宏展开的部分)完全不知道函数调用、变量和类似结构的内容。它只是进行文本替换,而不考虑文本的含义。(实际上是基于“标记”定义的。)
这意味着您可以滥用预处理器来做一些危险的事情。这里有一个例子。

谢谢这个,非常有用的信息。我是否理解正确,只要我始终将宏放在<>中,它们就不会被解释为数字?英语不是我的母语,所以我不能百分之百确定你在示例中的意思。 - natli
@natli:例子42.c几乎是故意混淆的;你最好忽略它。它强调了宏展开为算术表达式的点,但这里并不适用。我不明白你关于<>的问题是什么意思。字符串字面值恰好以“'<'”开头,以“'>'”结尾,但这与任何事情都没有特别相关。在示例程序中定义的“RECIPIENT”宏是为了给字符串赋予有意义的名称,目的是使示例代码更易于阅读和理解。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接