我们有一个表需要静态初始化,但是 MSVC (2015.1 和早期版本) 会生成动态初始化程序。
这是一个演示问题的简化代码:
#define idaapi __stdcall
#define MAXSTR 1024
typedef int error_t;
typedef unsigned char uchar;
struct psymbol_t
{
short what; /* -1 - is error, */
/* 0 - any symbol,don't skip it */
/* else lxtype_t */
short callNumber; /* Number in table of metasymbols */
/* -1 - no metasymbol */
/* Error code if what == -1 */
uchar nextNumber; /* Number in current table */
/* 0xFF - end */
uchar actNumber; /* Number in Actions table */
/* 0xFF - no action */
};
class parser_t;
typedef error_t (idaapi parser_t::*action_t)(void);
typedef error_t (idaapi parser_t::*nexttoken_t)(void);
struct token_t
{
int type; ///< see \ref lx_
char str[MAXSTR]; ///< idents & strings
};
class basic_parser_t
{
nexttoken_t gettok;
const psymbol_t *const *Table;
const action_t *Actions;
bool got_token;
public:
token_t ahead;
//bool exported_parse(int goal) { return basic_parser_parse(this, goal); }
};
class parser_t: public basic_parser_t {
public:
/* 0 */ error_t idaapi aArrayStart(void);
/* 1 */ error_t idaapi aComplexEnd(void);
/* 2 */ error_t idaapi aObjectStart(void);
/* 3 */ error_t idaapi aObjectKvpNew(void);
/* 4 */ error_t idaapi aObjectKvpKey(void);
/* 5 */ error_t idaapi aConstant(void);
};
static const action_t Acts[] =
{
/* 0 */ &parser_t::aArrayStart,
/* 1 */ &parser_t::aComplexEnd,
/* 2 */ &parser_t::aObjectStart,
/* 3 */ &parser_t::aObjectKvpNew,
/* 4 */ &parser_t::aObjectKvpKey,
/* 5 */ &parser_t::aConstant
};
使用 /FAs /c
编译会在 .asm 文件中生成 'Acts' 的动态初始化函数
,而不是一个漂亮的常量数组。
将最后一个 const
替换为 constexpr
会产生以下警告:
t.cpp(54): error C2131: 表达式未评估为常量
t.cpp(54): note: 非常量 (子) 表达式被遇到
然而我没有看到这里有什么非常量。有什么提示吗?
parser_t
之后使用typedef
函数指针会怎样呢?是的,为了做到这一点,您需要注释掉Table
和Actions
。只是一个想法... - Ajay/vmv
编译时,查看答案是否有所改变。对于前向声明类的成员指针,MSVC会出现问题。它试图聪明地处理这些指针的大小(违反了标准),但为此需要知道类的布局。/vmv
恢复了符合标准的行为(代价是使所有这样的指针都变成16字节)。 - Igor Tandetniktypedef
的想法是反向的。我已经添加了一个答案,应该可以解决你的问题。 - Jed Schaaf