您的位置:首页 > 其它

为什么头文件中不要写函数定义

2014-03-22 22:46 253 查看
        昨天看了一下预编译头文件的问题,领会到了预编译头文件的强大用处。于是乎,手痒尝试之。编写一甚为简单的小程序。程序的大概框架如下:

/*preCompeiledTest.cpp:*/

#include "print_out.h"

int main()
{
print_out();
}

/*print_out.h:*/

#include <stdio.h>
inline voidprint_out()
{
printf("Hello world");
}

/*stdafx.h:*/

#if !defined(AFX_STDAFX_H__A91FAFC6_F875_48E0_AB6F_561191F0ED77__INCLUDED_)
#defineAFX_STDAFX_H__A91FAFC6_F875_48E0_AB6F_561191F0ED77__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define WIN32_LEAN_AND_MEAN      // Exclude rarely-used stuff from Windowsheaders
#include <stdio.h>
#include "print_out.h"

/*stdafx.cpp:*/

#include"stdafx.h"


        基本代码内容和文件的关系就是这样,先编译了一下, 没问题!编译通过!接着链接,然而在链接过程中出现了如下问题:

error LNK2005:"void __cdecl print_out(void)" (?print_out@@YAXXZ) already defined inpreCompeiled.obj

 

fatal errorLNK1169: one or more multiply defined symbols found

 

 

 

      很明显这是个链接错误,而且是一个链接时期的重复定义问题。从这里我们能看到在头文件中最好还是不要定义函数,只做函数声明。若真要定义的话,在头文件所定义的函数前加上inline 使之成为内联函数即可。

分析一下其中原因,为什么在编译期可以通过而在链接期却发现问题。

       由于两个cpp文件所使用的函数或者变量,都在其所包含的文件当中,编译器在检查编译依赖时,完全可以找到相关的定义,由于void  print_out()函数是在头文件中定义的,编译器独立编译两个cpp文件是完全可以通过的,生成两个obj文件,并且这个头文件被编译两次,同一个函数,void  print_out()都独立被编译进两个obj文件中。然而在链接期间,链接器发现两个obj中都有void print_out()。虽然这两个实质就是同一个头文件中的定义,但是链接器不知道编译器是怎么编译的,它不承认你俩是同一个东西,并放你过去。他只会觉得混乱,不知道在链接之后,到底应该调用哪个print_out()。这就相当于,两个不同的头文件中都有函数名,参数,返回值等完全相同的函数,哪怕是在其对应的cpp文件中定义的。那么在一个主cpp文件中包含这两个不同的头文件,并使用函数名调用这个函数,那么链接时出现的情况同上,也是重复定义。此时链接器罢工了,他就报一个重复定义的错误。

      那么为什么我们加上inline,使头文件中的函数成为内联函数就可以正常编译链接运行呢了?

      我们知道,内联函数在编译期间,会将所有调用该内联函数的地方用内联函数完整的内容替替换,这种替换是一种文本式的替换。因此,在两份cpp文件中,由于打印函数所处的地方不一样,两个print_out()就是天然不同的,因此编译链接都是没有问题的。

      通常我们的做法是不在头文件中定义函数或定义变量,都只是函数或变量的声明。

具体的定义由对应的cpp文件完成。那么为什么这样的方式就不会出现连接错误呢?

      若以这样的方式写的话,对于print_out()的头文件和cpp文件可以独立编译,而其他需要调用该函数的文件则只需要包含其.h文件即可。其他文件编译时,不会对print_out()的cpp文件重新编译,并放进自己的obj中,而只是对其引用而已。因此在链接时,链接器知道print_out()的来源,自然链接过程中不会出现以上的问题了。

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐