如何在 C 或C++宏中使用函数作为文字字符串

how to use function as literal string in C or C++ macro

本文关键字:函数 字符串 文字 C++      更新时间:2023-10-16

我昨天发布了一个类似的问题,该网站建议发布一个新问题,并提供更好的解释。

有两个宏:

#define COMPANY L"Test Company"
#define PRODUCT COMPANY L" in Canada"

产品的结果将是"加拿大的测试公司"。

现在,我们有以下要求:

  1. 使 COMPANY 成为"动态"字符串,调用函数返回公司名称,例如 #define COMPANY getCompanyName()
  2. 我们不允许更改其他代码来引用公司,例如 #define 产品公司L"在加拿大",因为代码中有太多宏

更改的问题:PRODUCT的结果将是"测试公司",失去部分"在加拿大"字面。

这是代码:

#include <stdio.h>
#include <tchar.h>
const wchar_t* getCompanyName() { return L"Test Company";};
#define COMPANY getCompanyName();
#define PRODUCT COMPANY L" in Canada"
int _tmain(int argc, _TCHAR* argv[])
{
const wchar_t * company = COMPANY; // get Test Company
const wchar_t * product = PRODUCT; // get Test Company in Canada
wprintf(company);
wprintf(product);

return 0;
} 

这是一个令人讨厌的黑客,但实际上是可能的。定义表达式的COMPANY,该表达式以文本开头,以文本结尾,并且可以隐式转换为const wchar_t *

#define COMPANY L"" + getCompanyName() + L""

当然getCompanyName()不能返回const wchar_t *,因为operator+不是为两个指针定义的,无论如何它都可以处理地址而不是字符串。

你基本上需要std::wstring,但你可能需要它可以转换为const wchar_t *,而std::wstring不是。所以你必须定义自己的类:

struct AutoConvertibleString {
    std::string s;
    AutoConvertibleString(const std::string &s) : s(s) {}
    // C++ optimization for move:
    // AutoConvertibleString(std::string s) : s(std::move(s)) {}
    operator const wchar_t *() { return s.c_str(); }
};
AutoConvertibleString operator+(const wchar_t *l, const AutoConvertibleString &r) {
    return (l + r.s).c_str();
}
AutoConvertibleString operator+(const AutoConvertibleString &l, const wchar_t *r) {
    return (l.s + r).c_str();
}
// Ok, the operator+s could be optimized to use move for temporaries too...
AutoConvertibleString getCompanyName() { /* ... whatever ... */ }

这是一个丑陋的黑客。将它们全部转换为函数确实会更好。但它应该有效。

PRODUCT宏展开

getCompanyName(); L" in Canada"

所以

const wchar_t * product = getCompanyName(); L" in Canada";
wprintf(product);

指纹

Test Company

不出所料。

在C++,我们倾向于:

  • 避免宏(改用内联函数)
  • 避免裸指针(首选 STL 设施)

因此,在C++中,我们更喜欢:

inline const std::wstring getCompanyName() { return L"Test Company";}
inline const std::wstring PRODUCT() { return getCompanyName() + L" in Canada";}