我们可以看到由 C++ 实例化的模板吗?编译器?

发布于 2024-10-07 20:36:09 字数 373 浏览 0 评论 0原文

有没有办法查看 C++ 中函数模板或类模板的编译器实例化代码?

假设我有以下代码:

template <class T> T add(T a, T b) {
    return a + b;
}

当我调用时:

add<int>(10, 2); 

... 我想查看编译器为 int 模板专门化创建的函数。

我正在使用 g++、VC++,并且需要了解编译器选项来实现此目的。

Is there a way to see the compiler-instantiated code for a function template or a class template in C++?

Assume I have the following piece of code:

template <class T> T add(T a, T b) {
    return a + b;
}

When I call:

add<int>(10, 2); 

... I would like to see the function that the compiler creates for the int template specialization.

I am using g++, VC++, and need to know the compiler options to achieve this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

攒一口袋星星 2024-10-14 20:36:09

Clang (https://clang.llvm.org/) 可以漂亮地打印实例化模板的 AST

:示例:

test.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);
}

Clang (https://clang.llvm.org/) can pretty-print AST of instantiated template:

For your example:

test.cpp

template < class T> T add(T a, T b){
    return a+b;
}

void tmp() {
    add<int>(10,2); 
}

Command to pretty-print AST:

$ clang++ -Xclang -ast-print -fsyntax-only test.cpp

Clang-5.0/Clang 14.0 output:

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);
}
小矜持 2024-10-14 20:36:09

如果您想查看汇编输出,请使用此:

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;

(我通过引用传递参数以使输出更有趣)

If you want to see the assembly output, use this:

g++ -S file.cpp

If you want to see some (pseudo) C++ code that GCC generates, you can use this:

g++ -fdump-tree-original file.cpp

For your add function, this will output something like

;; Function T add(const T&, const T&) [with T = int] (null)
;; enabled by -tree-original

return <retval> = (int) *l + (int) *r;

(I passed the parameters by reference to make the output a little more interesting)

一直在等你来 2024-10-14 20:36:09

现在有一个在线工具可以为您执行此操作: 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));
}

https://cppinsights.io/s/0b914fd3

Now there is an on-line tool which does this for you: https://cppinsights.io/ For example, this code

template<class X, class Y> auto add(X x, Y y) {
  return x + y;
}

int main()
{
  return add(10, 2.5);
}

Is translated to

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));
}

https://cppinsights.io/s/0b914fd3

寂寞笑我太脆弱 2024-10-14 20:36:09

您绝对可以使用“-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)

You can definitely see the assembly code generated by the g++ using the "-S" option.

I don't think it is possible to display the "C++" equivalent template code - but I would still want a g++ developer to chime in why - I don't know the architecture of gcc.

When using assembly, you can review the resulting code looking for what resembles your function. As a result of running gcc -S -O1 {yourcode.cpp}, I got this (AMD64, gcc 4.4.4)

_Z3addIiET_S0_S0_:
.LFB2:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    leal    (%rsi,%rdi), %eax
    ret
    .cfi_endproc

Which really is just an int addition (leal).

Now, how to decode the c++ name mangler? there is a utility called c++filt, you paste the canonical (C-equivalent) name and you get the demangled c++ equivalent

qdot@nightfly /dev/shm $ c++filt 
_Z3addIiET_S0_S0_ 
int add<int>(int, int)
若无相欠,怎会相见 2024-10-14 20:36:09

当优化器完成其工作后,您很可能没有留下任何看起来像函数调用的东西。在您的具体示例中,最糟糕的是,您肯定会得到内联添加。除此之外,您始终可以在编译期间在单独的文件中发出生成的汇编程序,这就是您的答案。

When the optimizer has done its deeds, you most likely have nothing left that looks like a function call. In your specific example, you'll definitely end up with an inlined addition, at worse. Other than that, you can always emit the generated assembler in a separate file during compilation, and there lies your answer.

箹锭⒈辈孓 2024-10-14 20:36:09

最简单的是检查生成的程序集。您可以通过使用 g++ 的 -S 标志来获取汇编源代码。

The easiest is to inspect the generated assembly. You can get an assembly source by using -S flag for g++.

-黛色若梦 2024-10-14 20:36:09

我认为 c++ Insights 就是你想要的。

I think c++ Insights is what you want.

习ぎ惯性依靠 2024-10-14 20:36:09

如果您正在寻找等效的 C++ 代码,那么就没有。编译器永远不会生成它。编译器直接生成中间表示比首先生成 C++ 要快得多。

If your looking for the equivalent C++ code then no. The compiler never generates it. It's much faster for the compiler to generate it's intermediate representation straight off than to generate c++ first.

戈亓 2024-10-14 20:36:09

我知道这已经很旧了,但是对于现代 g++,您可以使用:

g++ -fdump-tree-*switch* -o array_size array_size.cpp

对于 switch 使用 all 来查看所有可以使用的类型,您将获得大约 32 个文件,其中一些文件非常大。您可以使用文件名的最后一个部分作为开关来获取该文件,例如-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”。

I know this is old, however for modern g++ you can use:

g++ -fdump-tree-*switch* -o array_size array_size.cpp

for switch use all to see all the types that can be used, you'll get about 32 files some are really big. You can use the last component of the file name as the switch to get just that file such as -fdump-tree-gimple.

This code:

#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;
}

Turns into:
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++ and search for "dump".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文