您的位置:首页 > 其它

inline陷阱问题

2015-08-05 12:46 896 查看
在规范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;
}


这样就符合上面的原则了

参考资料
/article/2802527.html
http://www.newsmth.net/bbscon.php?bid=335&id=146496
http://gcc.gnu.org/ml/gcc-prs/2002-11/msg01211.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: