我正在玩GCC(4.9.2)abi :: __ cxa_demangle,我遇到了一个无法解码特定符号名称的情况。
该符号为:
function myStringFromCharCode(which) {
var strKey = String.fromCharCode(which);
switch(which) {
case 13: return "Shift"
case 17: return "Ctrl"
case 18: return "Alt"
// add more mappings here ...
}
return strKey;
}
function myOnKeyUp(e) {
alert(e.which + "=" + myStringFromCharCode(e.which));
}
document.body.onkeyup=myOnKeyUp;
我很惊讶地看到“declval”。
使用此宏定义该特定函数:
_ZNK12DebugWrapperIR5TestClsE5getIdIIEEEDTcldtcl7declvalIS1_EEL_ZNKS0_5getIdEvEspfp_EEDpOT_
我也通过itanium c++ abi spec快速搜索了declval但没有结果。
为什么会这样?为什么不能abi :: __ cxa_demangle demangle呢?
答案 0 :(得分:2)
模板函数需要使其返回类型出现在错位名称中,因为模板函数可以仅在返回类型上重载。一个更简单的例子是
template <typename T> void f() { }
template <typename T> auto g() -> decltype(f<T>()) { }
inline void h() { }
int main() { g<int>(); h(); }
编译并检查输出,我看到:
$ g++ -c h.cc -std=c++11 && nm h.o | c++filt 0000000000000000 T main 0000000000000000 W decltype ((f)()) g() 0000000000000000 W h()
您可以在g
看到返回类型,但不能查看h
的返回类型。 h
不是模板函数的事实已经意味着在具有相同参数的同一名称空间中不能有另一个函数h
。
这也是getId
在您的错位名称中出现两次的原因。其中一个是名称本身,另一个是它在返回类型中的外观。
declval
在这里并不特别,这就是为什么它没有在C ++ ABI中被调用。任何函数,库或用户都会以同样的方式处理。
至于为什么它不会消失,这很难说。在您的问题中生成错位名称的真实代码示例会有所帮助,但5TestCls
看起来不对,因为名称前面的数字表示长度,我确实得到TestCls
的印象应该是全名。如果这确实是名称,那么demangling会失败,因为受损的名称无效。
根据您在评论中发布的完整示例,我可以提出一个简化的程序,看起来它是成员访问运算符,但是demangler没有正确处理:
extern struct A { void f(); static void g(); } a;
template <typename...T> auto f(T...t) -> decltype(a.f(t...));
template <typename...T> auto g(T...t) -> decltype(A::g(t...));
int main() { f(); g(); }
$ g++ -std=c++11 -pedantic -c h.cc && nm h.o && nm -C h.o 0000000000000000 T main U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ U _Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_ 0000000000000000 T main U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ U decltype (A::g({parm#1}...)) g<>()
_Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_
和_Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_
之间的差异更明显,有一些额外的间距:
_Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_ _Z1gIJEEDTcl L_ZN1A1gEvEspfp_EEDpT_
唯一的区别是f
与g
和dtL_Z1aE
。
Itanium C ++ ABI指定x.y
被修改为dt <expression> <unresolved-name>
。在此,<expression>
为L_Z1aE
。那部分看起来正确。这表明a
全局变量的“受损”(非真实)名称。但<unresolved-name>
是_ZN1A1fEvE
。那是错的。这适用于decltype(A::g(t...))
版本,其中函数调用操作符的最左侧操作数可以通过<expr-primary> ::= L <mangled-name> E
生成表示为错位名称,但不适用于decltype(a.f(t...))
版本。这意味着类似A::f()
,但<unresolved-name>
不应该具有命名空间限定符,除非它们实际出现在源代码中,即使这样,也只有一个特殊的前缀(sr
)。它也不应该有参数信息。 <unresolved-name>
应为1f
。
如果使用了更正的名称,则解码器可以处理它:
$ c++filt <<< _Z1fIJEEDTcldtL_Z1aE1fspfp_EEDpT_ decltype ((a.f)({parm#1}...)) f<>()
clang会生成正确的名称,只需在命令调用中将g++
更改为clang++
即可在Coliru上看到。您可能希望将此报告为GCC开发人员的错误。