首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从内联函数调用内联函数?

从内联函数调用内联函数?
EN

Stack Overflow用户
提问于 2015-05-19 18:40:40
回答 4查看 249关注 0票数 0

这个问题听起来太简单了,不能在某个地方得到回答,但我试着环顾四周,找不到任何简单的答案。下面是一个例子:

代码语言:javascript
复制
class vec
{
   double x;
   double y;
};

inline void sum_x(vec & result, vec & a, vec & b)
{
   result.x = a.x + b.x;
}

inline void sum(vec & result, vec & a, vec & b)
{
   sum_x(result, a, b);
   result.y = a.y + b.y;
}

当我调用sum并编译时会发生什么?sumsum_x是否都是内联的,这样它就会转换成内联汇编代码来对这两个组件求和?

这看起来像一个微不足道的例子,但我使用的是一个在模板中定义了维数的向量类,所以迭代向量上的操作看起来有点像这样。

EN

回答 4

Stack Overflow用户

发布于 2015-05-19 18:46:09

inline只是对编译器的一个提示。编译器是否真正内联函数则是另一个问题。对于gcc来说,有一个always inline属性来强制执行此操作。

代码语言:javascript
复制
 __attribute__((always_inline));

通过始终内联,你应该实现你所描述的(代码生成,就好像它是在一个函数中编写的一样)。

但是,对于编译器应用的所有优化和转换,只有检查生成的代码(程序集)才能确定

票数 2
EN

Stack Overflow用户

发布于 2015-05-19 18:45:14

是,内联可以递归应用。

您在这里执行的整个操作集都可以在调用点内联。

请注意,这与您使用inline关键字没有多大关系,该关键字(除了对ODR的影响之外--这一点非常明显)只是一个提示,目前在实际内联时通常忽略该关键字。函数将被内联,因为您聪明的编译器可以看到它们是很好的候选函数。

您可以实际知道它是否正在执行此操作的唯一方法是自己检查生成的程序集。

票数 1
EN

Stack Overflow用户

发布于 2015-05-19 18:50:02

那得看情况。inline只是对编译器的一个提示,它可能想要考虑内联该函数。编译器完全可以内联这两个调用,但这取决于实现。

作为一个例子,这里有一些来自GCC的美化汇编输出,其中包含和不包含这个简单程序的inline

代码语言:javascript
复制
int main()                                                                      
{           
  vec a;
  vec b;
  std::cin >> a.x;
  std::cin >> a.y;

  sum(b,a,a);
  std::cout << b.x << b.y;
    return 0;
}

使用内联:

代码语言:javascript
复制
main:
    subq    $40, %rsp
    leaq    16(%rsp), %rsi
    movl    std::cin, %edi
    call    std::basic_istream<char, std::char_traits<char> >& std::basic_istream<char, std::char_traits<char> >::_M_extract<double>(double&)
    leaq    24(%rsp), %rsi
    movl    std::cin, %edi
    call    std::basic_istream<char, std::char_traits<char> >& std::basic_istream<char, std::char_traits<char> >::_M_extract<double>(double&)
    movsd   24(%rsp), %xmm0
    movapd  %xmm0, %xmm1
    addsd   %xmm0, %xmm1
    movsd   %xmm1, 8(%rsp)
    movsd   16(%rsp), %xmm0
    addsd   %xmm0, %xmm0
    movl    std::cout, %edi
    call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
    movsd   8(%rsp), %xmm0
    movq    %rax, %rdi
    call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
    movl    $0, %eax
    addq    $40, %rsp
    ret
    subq    $8, %rsp
    movl    std::__ioinit, %edi
    call    std::ios_base::Init::Init()
    movl    $__dso_handle, %edx
    movl    std::__ioinit, %esi
    movl    std::ios_base::Init::~Init(), %edi
    call    __cxa_atexit
    addq    $8, %rsp
    ret

没有:

代码语言:javascript
复制
sum_x(vec&, vec&, vec&):
    movsd   (%rsi), %xmm0
    addsd   (%rdx), %xmm0
    movsd   %xmm0, (%rdi)
    ret
sum(vec&, vec&, vec&):
    movsd   (%rsi), %xmm0
    addsd   (%rdx), %xmm0
    movsd   %xmm0, (%rdi)
    movsd   8(%rsi), %xmm0
    addsd   8(%rdx), %xmm0
    movsd   %xmm0, 8(%rdi)
    ret
main:
    pushq   %rbx
    subq    $48, %rsp
    leaq    32(%rsp), %rsi
    movl    std::cin, %edi
    call    std::basic_istream<char, std::char_traits<char> >& std::basic_istream<char, std::char_traits<char> >::_M_extract<double>(double&)
    leaq    40(%rsp), %rsi
    movl    std::cin, %edi
    call    std::basic_istream<char, std::char_traits<char> >& std::basic_istream<char, std::char_traits<char> >::_M_extract<double>(double&)
    leaq    32(%rsp), %rdx
    movq    %rdx, %rsi
    leaq    16(%rsp), %rdi
    call    sum(vec&, vec&, vec&)
    movq    24(%rsp), %rbx
    movsd   16(%rsp), %xmm0
    movl    std::cout, %edi
    call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
    movq    %rbx, 8(%rsp)
    movsd   8(%rsp), %xmm0
    movq    %rax, %rdi
    call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
    movl    $0, %eax
    addq    $48, %rsp
    popq    %rbx
    ret
    subq    $8, %rsp
    movl    std::__ioinit, %edi
    call    std::ios_base::Init::Init()
    movl    $__dso_handle, %edx
    movl    std::__ioinit, %esi
    movl    std::ios_base::Init::~Init(), %edi
    call    __cxa_atexit
    addq    $8, %rsp
    ret

正如您所看到的,当被要求时,GCC内联了这两个函数。

如果您的程序集有点生疏,只需注意在第二个版本中存在并调用了sum,但在第一个版本中没有。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30323325

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档