汇编TypeID(OBJ)时会发生什么-C
what happens when typeid(obj) is compiled - C++
我的程序中有一个示例类,如
template<class T>
class MyTemplate1
{
public:
T a;
MyTemplate1(T other){
a = other;
}
};
在我的主要程序中,如果我只是创建类型MyTemplate1<int>
的对象,则不会在ReadElf输出中显示任何typeInfo对象。但是,如果我添加一些代码,例如
MyTemplate1<int> obj = 12;
if(typeid(obj) == typeid(MyTemplate1<float>))
//some code
READELF输出显示MyTemplate1<int>
的类型Info和MyTemplate1<float>
的TypeInfo。
$readelf -s -W <objfile> | findstr -I "MyTemplate"
9023: 00000000 8 OBJECT WEAK DEFAULT 2899 _ZTI11MyTemplate1IfE
9024: 00000000 8 OBJECT WEAK DEFAULT 2894 _ZTI11MyTemplate1IiE
有人可以解释这些对象与什么相对应吗?这些std :: type_info的全局实例是MyTemplate1的这些全局实例吗?引擎盖下到底发生了什么?
您不需要构造任何对象实例化MyTemplate1<T>
在汇编单元中查看描述实例类别类的typeInfo对象该模板在对象文件的全局符号表中。您只需要参考此类类的typeid
: -
$ cat main.cpp
#include <typeinfo>
template<class T>
class MyTemplate1
{
public:
T a;
MyTemplate1(T other){
a = other;
}
};
int main(void)
{
return (typeid(MyTemplate1<int>) == typeid(MyTemplate1<float>));
}
$ clang++ -Wall -c main.cpp
$ readelf -s -W main.o | grep MyTemplate1
5: 0000000000000000 16 OBJECT WEAK DEFAULT 15 _ZTI11MyTemplate1IfE
6: 0000000000000000 16 OBJECT WEAK DEFAULT 10 _ZTI11MyTemplate1IiE
7: 0000000000000000 17 OBJECT WEAK DEFAULT 13 _ZTS11MyTemplate1IfE
8: 0000000000000000 17 OBJECT WEAK DEFAULT 8 _ZTS11MyTemplate1IiE
$ c++filt _ZTI11MyTemplate1IfE
typeinfo for MyTemplate1<float>
$ c++filt _ZTI11MyTemplate1IiE
typeinfo for MyTemplate1<int>
$ c++filt _ZTS11MyTemplate1IfE
typeinfo name for MyTemplate1<float>
$ c++filt _ZTS11MyTemplate1IiE
typeinfo name for MyTemplate1<int>
这些typeinfo
对象存在,因为,如@Peter注释,C 标准要求typeid
是指静态存储持续时间的对象
引擎盖下到底发生了什么?
您可能会想知道:为什么编译器将这些typeinfo
对象符号弱而不是简单的全局?为什么它在对象文件的不同部分中定义它们?(我的对象文件的第10节和第15节,您的第2894和2899节)。
,如果我们检查了这些部分中的 else :
$ readelf -s main.o | egrep '(10 |15 )'
5: 0000000000000000 16 OBJECT WEAK DEFAULT 15 _ZTI11MyTemplate1IfE
6: 0000000000000000 16 OBJECT WEAK DEFAULT 10 _ZTI11MyTemplate1IiE
我们看到每个对象都是其部分中唯一的东西。为什么呢?
在我的main.o
中,第10节和15节是:
$ readelf -t main.o | egrep '([10]|[15])'
[10] .rodata._ZTI11MyTemplate1IiE
[15] .rodata._ZTI11MyTemplate1IfE
每个都是仅读取的数据表,其意义是:
__attribute__((section(.rodata._ZTI11MyTemplate1IiE)))
__attribute__((section(.rodata._ZTI11MyTemplate1IfE)))
包含除了 之后的对象的定义命名。
编译器为每个对象提供一个数据截面它制作符号WEAK
的原因相同。对typeid(MyTemplate1<X>)
的引用,对于任意类型的X
,可以在#include
的相同链接中的多个翻译单元的定义 MyTemplate1
。在这种情况下,要使用多重定义错误来解决链接失败,编译器使符号虚弱。链接器将容忍弱符号的多个定义,解决所有参考都仅仅指出了第一个定义,并忽略了其余的部分。通过将唯一的数据图(或适当的功能部分)专用于编译器的每个弱模板启用符号的定义使链接器自由丢弃任何剩余数据或功能的部分,这些部分定义了相同的弱符号该计划造成附带损害的风险。请参阅:
$ cat MyTemplate1.hpp
#pragma once
template<class T>
class MyTemplate1
{
public:
T a;
MyTemplate1(T other){
a = other;
}
};
$ cat foo.cpp
#include "MyTemplate1.hpp"
#include <typeinfo>
int foo()
{
return typeid(MyTemplate1<int>) == typeid(MyTemplate1<float>);
}
$ cat bar.cpp
#include "MyTemplate1.hpp"
#include <typeinfo>
int bar()
{
return typeid(MyTemplate1<int>) != typeid(MyTemplate1<float>);
}
$ cat prog.cpp
extern int foo();
extern int bar();
int main()
{
return foo() && bar();
}
如果我们编译:
$ clang++ -Wall -c prog.cpp foo.cpp bar.cpp
和链接(带有一些诊断):
$ clang++ -o prog prog.o bar.o foo.o
-Wl,-trace-symbol=_ZTI11MyTemplate1IfE
-Wl,-trace-symbol=_ZTI11MyTemplate1IiE
-Wl,-Map=mapfile
/usr/bin/ld: bar.o: definition of _ZTI11MyTemplate1IfE
/usr/bin/ld: bar.o: definition of _ZTI11MyTemplate1IiE
/usr/bin/ld: foo.o: reference to _ZTI11MyTemplate1IfE
/usr/bin/ld: foo.o: reference to _ZTI11MyTemplate1IiE
在foo.o
之前输入bar.o
,然后链接器选择的定义 _ZTI11MyTemplate1I(f|i)E
的CC_17,无视foo.o
中的定义,将foo.o
中的引用解析到bar.o
中的定义。MapFile显示:
mapfile(1)
...
Discarded input sections
...
.rodata._ZTI11MyTemplate1IiE
0x0000000000000000 0x10 foo.o
...
.rodata._ZTI11MyTemplate1IfE
0x0000000000000000 0x10 foo.o
...
foo.o
中的定义被抛弃了。如果我们重新链接bar.o
和foo.o
的订单相反:
$ clang++ -o prog prog.o foo.o bar.o
-Wl,-trace-symbol=_ZTI11MyTemplate1IfE
-Wl,-trace-symbol=_ZTI11MyTemplate1IiE
-Wl,-Map=mapfile
/usr/bin/ld: foo.o: definition of _ZTI11MyTemplate1IfE
/usr/bin/ld: foo.o: definition of _ZTI11MyTemplate1IiE
/usr/bin/ld: bar.o: reference to _ZTI11MyTemplate1IfE
/usr/bin/ld: bar.o: reference to _ZTI11MyTemplate1IiE
然后我们得到相反的结果。foo.o
的定义已链接和:
mapfile(2)
...
Discarded input sections
...
.rodata._ZTI11MyTemplate1IiE
0x0000000000000000 0x10 bar.o
...
.rodata._ZTI11MyTemplate1IfE
0x0000000000000000 0x10 bar.o
...
bar.o
中的那些被扔掉了。这是第一个首次上课的链接器的原理很好,因为 - 和仅,因为 - 编译器找到的template<class T> MyTemplate1
的定义在翻译单元中,foo.cpp
与bar.cpp
中发现的单元相同条件C 标准需要,在一个定义规则中,但是C 编译器对 emforce 。
通常,您可以对模板构成符号进行基本相同的观察结果,而您对Clang 的看到的观察与G 所看到的基本相同。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 什么时候在C++中返回常量引用是个好主意
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- C++避免重复声明的语法是什么
- c++库的公共头文件中应该包含什么
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- ifstream什么都没读
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- typeid 运算符忽略 cv 限定符背后的理由是什么?
- 汇编TypeID(OBJ)时会发生什么-C
- 这个号码和我的typeid有什么关联
- 什么时候使用"typeid"是最好的解决方案?