预处理器交换参数
Preprocessor swaps arguments
我有一些代码需要文本表示形式的值和与十六进制表示形式相同的值。我需要两者,但为了消除潜在的错误来源,我只想指定一次值并让预处理器处理它。
这是其中一项的示例。
int[] v = { 0x01, 0x02 };
LPCTSTR s = L"0102";
预处理器连接在这方面提供了强大的帮助。
这是相同的代码,但现在通过预处理器命令。
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#define _S(t) _T(STRING2(t))
#define _H(t) 0x ## t
#define _VS(a,b) _S(a) _S(b)
#define _VH(a,b) _H(a),_H(b)
LPCTSTR s = _VS(01, 02);
int[] v = { _VH(01, 02) };
预处理器生成的代码如下所示:
int[] v = { 0x01,0x02 };
LPCTSTR s = L"01" L"02";
但我仍在重复我的数据。所以,我试试这个。
#define ARGUMENTS 01, 02
LPCTSTR s = _VS(ARGUMENTS);
int[] v = { _VH(ARGUMENTS) };
现在预处理器代码被破坏了!
int[] v = { 0x01, 02,0x };
LPCTSTR s = L"01" L;
请注意,第二个参数和它应该连接的标记部分被交换或丢失。但是为什么?
VS2010 help page 对我帮助不大。它告诉我连接运算符正在对宏扩展进行约束。这很可能是扩展宏 ARGUMENTS 变得 foobar 的原因。
但是我怎样才能让它发挥作用呢?
额外的测试表明,阻止宏的进一步扩展的绝对是串联运算符。所以我需要一种方法来先扩展参数,然后使用连接运算符。好主意?现在怎么办!
欢迎提出任何建议。
我觉得您应该将定义重写为 XMacros。这是一种巧妙的技术,可以让您编写一个包含数据定义的文件(通常带有 .def
扩展名),如下所示:
VAL(01)
VAL(02)
比您简单地定义一个适当的宏,并包含以获得所需的结构,如下所示:
#define VAL(x) _H(x),
int[] v = {
#include "values.def"
};
#undef VAL
#define VAL(x) _S(x)
LPCTSTR s =
#include "values.def"
;
#undef VAL
因为 ARGUMENTS
仍然是单个值,您可以在两个输出中清楚地看到这一点 - ARGUMENTS
被视为单个参数,然后是第二个 的处理empty 参数(gcc 实际上更有帮助,并丢弃了 error: macro "_VS" requires 2 arguments, but only 1 given
的预处理)。
要实现你想要的,试试这个:
#define MK_STRING_INT_PAIR(a,b,sname,vname) \
LPCTSTR sname=_VS(a,b); \
int[] vname={_VH(a,b)};
MK_STRING_INT_PAIR(01,02,s,v)
[编辑]
如果您需要超过 2 个值,请编写一个简短的程序来生成一个带有宏的 .h 文件:
#define MK_PAIRS_2(sname,vname,v0,v1) ...
#define MK_PAIRS_3(sname,vname,v0,v1,v3) ...
#define MK_PAIRS_128(sname,vname,....
正在生成,您将不需要依赖 _VS、_VH 辅助宏
(我从骨子里觉得在 C++11 中有可能使用可变参数模板和 char[] 类型的 constexpr-s 来做到这一点,但现在我没有时间去探索它).
我有一些代码需要文本表示形式的值和与十六进制表示形式相同的值。我需要两者,但为了消除潜在的错误来源,我只想指定一次值并让预处理器处理它。
这是其中一项的示例。
int[] v = { 0x01, 0x02 };
LPCTSTR s = L"0102";
预处理器连接在这方面提供了强大的帮助。 这是相同的代码,但现在通过预处理器命令。
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#define _S(t) _T(STRING2(t))
#define _H(t) 0x ## t
#define _VS(a,b) _S(a) _S(b)
#define _VH(a,b) _H(a),_H(b)
LPCTSTR s = _VS(01, 02);
int[] v = { _VH(01, 02) };
预处理器生成的代码如下所示:
int[] v = { 0x01,0x02 };
LPCTSTR s = L"01" L"02";
但我仍在重复我的数据。所以,我试试这个。
#define ARGUMENTS 01, 02
LPCTSTR s = _VS(ARGUMENTS);
int[] v = { _VH(ARGUMENTS) };
现在预处理器代码被破坏了!
int[] v = { 0x01, 02,0x };
LPCTSTR s = L"01" L;
请注意,第二个参数和它应该连接的标记部分被交换或丢失。但是为什么?
VS2010 help page 对我帮助不大。它告诉我连接运算符正在对宏扩展进行约束。这很可能是扩展宏 ARGUMENTS 变得 foobar 的原因。 但是我怎样才能让它发挥作用呢?
额外的测试表明,阻止宏的进一步扩展的绝对是串联运算符。所以我需要一种方法来先扩展参数,然后使用连接运算符。好主意?现在怎么办!
欢迎提出任何建议。
我觉得您应该将定义重写为 XMacros。这是一种巧妙的技术,可以让您编写一个包含数据定义的文件(通常带有 .def
扩展名),如下所示:
VAL(01)
VAL(02)
比您简单地定义一个适当的宏,并包含以获得所需的结构,如下所示:
#define VAL(x) _H(x),
int[] v = {
#include "values.def"
};
#undef VAL
#define VAL(x) _S(x)
LPCTSTR s =
#include "values.def"
;
#undef VAL
因为 ARGUMENTS
仍然是单个值,您可以在两个输出中清楚地看到这一点 - ARGUMENTS
被视为单个参数,然后是第二个 的处理empty 参数(gcc 实际上更有帮助,并丢弃了 error: macro "_VS" requires 2 arguments, but only 1 given
的预处理)。
要实现你想要的,试试这个:
#define MK_STRING_INT_PAIR(a,b,sname,vname) \
LPCTSTR sname=_VS(a,b); \
int[] vname={_VH(a,b)};
MK_STRING_INT_PAIR(01,02,s,v)
[编辑] 如果您需要超过 2 个值,请编写一个简短的程序来生成一个带有宏的 .h 文件:
#define MK_PAIRS_2(sname,vname,v0,v1) ...
#define MK_PAIRS_3(sname,vname,v0,v1,v3) ...
#define MK_PAIRS_128(sname,vname,....
正在生成,您将不需要依赖 _VS、_VH 辅助宏
(我从骨子里觉得在 C++11 中有可能使用可变参数模板和 char[] 类型的 constexpr-s 来做到这一点,但现在我没有时间去探索它).