有没有办法查看 C++ 中函数模板或类模板的编译器实例化代码?
假设我有以下代码:
template <class T> T add(T a, T b) {
return a + b;
}
当我打电话时:
add<int>(10, 2);
...我想查看编译器为
int
模板专业化创建的函数。
我正在使用 g++、VC++,并且需要了解编译器选项来实现此目的。
Clang (https://clang.llvm.org/) 可以漂亮地打印实例化模板的 AST:
举个例子:
测试.cpp
template < class T> T add(T a, T b){
return a+b;
}
void tmp() {
add<int>(10,2);
}
漂亮打印 AST 的命令:
$ clang++ -Xclang -ast-print -fsyntax-only test.cpp
Clang-5.0/Clang 14.0 输出:
template <class T> T add(T a, T b) {
return a + b;
}
template<> int add<int>(int a, int b) {
return a + b;
}
void tmp() {
add<int>(10, 2);
}
如果您想查看汇编输出,请使用以下命令:
g++ -S file.cpp
如果你想查看 GCC 生成的一些(伪)C++ 代码,你可以使用这个:
g++ -fdump-tree-original file.cpp
对于您的
add
函数,这将输出类似
;; Function T add(const T&, const T&) [with T = int] (null)
;; enabled by -tree-original
return <retval> = (int) *l + (int) *r;
(我通过引用传递参数以使输出更有趣)
现在有一个在线工具可以为您执行此操作:https://cppinsights.io/例如,此代码
template<class X, class Y> auto add(X x, Y y) {
return x + y;
}
int main()
{
return add(10, 2.5);
}
翻译为
template<class X, class Y> auto add(X x, Y y) {
return x + y;
}
/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
double add<int, double>(int x, double y)
{
return static_cast<double>(x) + y;
}
#endif
int main()
{
return static_cast<int>(add(10, 2.5));
}
您绝对可以使用“-S”选项看到g++生成的汇编代码。
我认为不可能显示“C++”等效模板代码 - 但我仍然希望 g++ 开发人员补充原因 - 我不知道 gcc 的体系结构。
使用汇编时,您可以查看生成的代码,查找与您的函数相似的代码。运行 gcc -S -O1 {yourcode.cpp} 的结果是,我得到了这个(AMD64,gcc 4.4.4)
_Z3addIiET_S0_S0_:
.LFB2:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
leal (%rsi,%rdi), %eax
ret
.cfi_endproc
这实际上只是一个 int 加法(leal)。
现在,如何解码 C++ 名称修饰器?有一个名为 c++filt 的实用程序,您粘贴规范(C 等效)名称,您将获得分解后的 C++ 等效名称
qdot@nightfly /dev/shm $ c++filt
_Z3addIiET_S0_S0_
int add<int>(int, int)
当优化器完成其工作后,您很可能没有留下任何看起来像函数调用的东西。在您的具体示例中,最糟糕的是,您肯定会得到内联添加。除此之外,您始终可以在编译期间在单独的文件中发出生成的汇编程序,这就是您的答案。
最简单的是检查生成的程序集。您可以通过使用 g++ 的 -S 标志来获取汇编源代码。
我认为 c++ Insights 就是你想要的。
如果您正在寻找等效的 C++ 代码,那么没有。编译器永远不会生成它。编译器直接生成中间表示比首先生成 C++ 要快得多。
我知道这已经很旧了,但是对于现代 g++ 你可以使用:
g++ -fdump-tree-*switch* -o array_size array_size.cpp
对于 switch 使用 all 查看所有可以使用的类型,您将得到大约 32 个文件,其中一些文件非常大。您可以使用文件名的最后一个部分作为 switch 来获取该文件,例如
-fdump-tree-gimple
。
此代码:
#include <iostream>
template <typename T, size_t N>
size_t ARRAYSIZET(T (&a)[N])
{
return N;
}
int main (int argc, char * argv[])
{
int a[] = {1,2,3,4,5,6};
std::cout << ARRAYSIZET(a) << std::endl;
}
变成: g++ -fdump-tree-gimple -o array_size array_size.cpp
int main (int argc, char * * argv)
{
int D.53868;
{
int a[6];
try
{
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;
a[5] = 6;
_1 = std::basic_ostream<char>::operator<< (&cout, 6);
std::basic_ostream<char>::operator<< (_1, endl);
_2 = ARRAYSIZET<int, 6> (&a);
_3 = std::basic_ostream<char>::operator<< (&cout, _2);
std::basic_ostream<char>::operator<< (_3, endl);
}
finally
{
a = {CLOBBER(eol)};
}
}
D.53868 = 0;
return D.53868;
}
size_t ARRAYSIZET<int, 6> (int[6] & a)
{
size_t D.53874;
D.53874 = 6;
return D.53874;
}
man g++ 并搜索“dump”。