码迷,mamicode.com
首页 > 其他好文 > 详细

inline陷阱问题

时间:2015-08-05 15:01:59      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:

在规范c++编程时遇到的,即类的文件定义

常规的对类的使用,在class.h对类进行生命,对于成员函数在class.cpp中定义,如下实现

main.cpp
#include<iostream>

#include "person.h"

using namespace std;


int main()
{
 person p;
 p.setage(12);
 cout<<p.backage()<<endl;

 return 0;
}

person.h
#ifndef _PERSON_H_
#define _PERSON_H_
class person
{
public:
  void setage(int n);
  int backage();
private:
 int age;
};
#endif

person.cpp
#include "person.h"
void person::setage(int n)
{
 age=n;
}
int person::backage()
{
 return age;
}

这里面有个问题就是  对于内联成员函数,这种写法是链接不通过的
即下面这种情况
class person
{
public:
 inline void setage(int n);
 inline int backage();
private:
 int age;
};
错误是
1>main.obj : error LNK2019: unresolved external symbol "public: int __thiscall person::backage(void)" (?backage@person@@QAEHXZ) referenced in function _main

看了一些博客,大概的问题在于,首先明白什么是内联函数,他的链接属性是什么
在c++03标准中
“  The inline keyword has no effect on the linkage of a function.“  
也就是说,inline没有所谓的必须内部链接属性和外部链接属性
因为inline是直接嵌入代码的,那么 是否可以直接调用这个函数,实验一下
在ubuntu中
下面简单代码
t.c文件
inline void f()
{
 int a;
 a++;
}

int main()
{
 f();
 return 0;
}
使用gcc -S t.c -o t.s
发现t.s中并没有将这个函数内联
f:
 pushq	%rbp
 movq	%rsp, %rbp
 addl	$1, -4(%rbp)
 popq	%rbp
 ret
main:
 pushq	%rbp
 movq	%rsp, %rbp
 movl	$0, %eax
 call	f
 movl	$0, %eax
 popq	%rbp
 ret
这是什么原因,网上将要将编译器优化
加上-O2 参数项
为了实验方便将c代码修改为
#include<stdio.h>
inline int f(int a)
{
 a++;
 printf("a=%d\n",a);
 return a;
}
int main()
{
 int b=0;
 b=f(b);
 printf("b=%d\n",b);
 return 0;
}
汇编代码为
main:
 subq	$8, %rsp
 movl	$1, %edx
 movl	$.LC0, %esi
 movl	$1, %edi
 xorl	%eax, %eax
 call	__printf_chk

 movl	$1, %edx
 movl	$.LC1, %esi
 movl	$1, %edi
 xorl	%eax, %eax
 call	__printf_chk  

 xorl	%eax, %eax
 addq	$8, %rsp
 ret



在main中发现就没有call函数了,而是内联成功了
所以有一点就是,inline只是请求编译器内联,是否内联不一定,除非加上编译参数强制内联。

然后下一个问题回到c++类中,为什么内联成员函数不能在其他文件中定义。
ISO-Standard有这样一句话
inline function shall be defined in every translation unit in which it is used and shall have exactly the same definition in every case.
并且有人对此做了研究,下面是对话
 >     File1.cc:
 >     ----------------snip here----------------
 >     inline int foo (int x) { return x; }
 >
 >     int bar() { return foo(2); }
 >     ----------------snip here----------------
 >
 >     File2.cc:
 >     ----------------snip here----------------
 >     inline int foo (int);
 >
 >     int main() { return foo(1); }
 >     ----------------snip here----------------
 >
 >     If I compile this using "g++ File1.cc File2.cc" I get a working
 program
 >     that returns 1. If I compile it with "-O" enabled, I get a linker
 error:
 >
 >       Unresolved text symbol "foo(int)" -- 1st referenced by
 /var/tmp//cckhU7pa.o.
 >
 >     Without optimization the function "foo" in the first file isn't
 inlined.
 >     But because it's used by "bar" it is put in the object file. With
 optimization
 >     the function is inlined and doesn't appear explicitly in the object
 file of
 >     the first file. Therefore, the linker error.
 >
 >     In essence: The compiler does not need to put inline functions in the
 object
 >     file. The compiler can just optimize them away. And because of that we
 have
 >     paragraph 7.1.2.4.

在main中发现就没有call函数了,而是内联成功了
所以有一点就是,inline只是请求编译器内联,是否内联不一定,除非加上编译参数强制内联。

然后下一个问题回到c++类中,为什么内联成员函数不能在其他文件中定义。
ISO-Standard有这样一句话
inline function shall be defined in every translation unit in which it is used and shall have exactly the same definition in every case.
并且有人对此做了研究,下面是对话

到此就明白了,在我上面的那个c++类中,如果main要调用内联的成员函数,那么在main所在的这个文件里必须要有内联函数的定义
所以修改为
main.cpp
#include<iostream>

#include "person.h"
#include "person.cpp"
using namespace std;


int main()
{
 person p;
 p.setage(12);
 cout<<p.backage()<<endl;

 return 0;
}


这样就符合上面的原则了





参考资料


版权声明:本文为博主原创文章,未经博主允许不得转载。

inline陷阱问题

标签:

原文地址:http://blog.csdn.net/u010442328/article/details/47295409

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!