【发布时间】:2016-07-02 04:13:45
【问题描述】:
我们想要静态初始化一个表,但是 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 文件中生成一个 dynamic initializer for 'Acts' 函数,而不是一个不错的常量数组。
将最后一个 const 替换为 constexpr 会产生以下警告:
t.cpp(54):错误 C2131:表达式未计算为常量
t.cpp(54):注意:遇到了一个非常量(子)表达式
但是我没有看到这里有什么是非常量的。有什么提示吗?
【问题讨论】:
-
(在 GCC 和 Clang (demo) 中工作正常。)
-
这可能是编译器/平台限制。 MS-Windows 上使用的目标模块格式可能不支持指向该类型函数的未解析符号。尝试使用指向普通函数的指针初始化静态 const 数组,并查看编译器是否生成动态初始化代码。
-
如果你 typedef' 定义了
parser_t之后的函数指针会怎样。是的,为此您需要注释掉Table和Actions。只是一个想法...... -
查看使用
/vmv编译时答案是否改变。指向前向声明类成员的指针会给 MSVC 带来麻烦。它试图巧妙地处理此类指针的大小(违反标准),但为此它需要知道类的布局。/vmv恢复符合标准的行为(以使所有此类指针变大 16 字节为代价)。 -
@IgorTandetnik 我认为您可能正在做某事,但
/vmv没有效果,以及在引用它们之前定义方法。我想我们可能不得不求助于方法的静态函数包装器......
标签: c++ arrays visual-c++ static-initialization