关于在头文件中实现函数的情况

下面举个例子,这个例子只有3个文件

/* fun.h */
#ifndef FUN_H
#define FUN_H
void base(){};
void fun();
#endif 

/* fun.c */
#include "fun.h"
void fun()
{
    base();
}

/* main.c */
#include "fun.h"
int main()
{
    fun();
    return 0;
}

$gcc -c fun.c

$gcc -c main.c

$gcc -o main main.c fun.c

则会在链接是时候报重复定义base()的错误!

fun.o: In function `base':
fun.c:(.text+0x0): multiple definition of `base'
main.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit statu

注:开始时在对这行忽然很陌生,main.c中的fun(); 突然搞不清这行代码做了什么事了!fun的函数体是调用base()方法,虽然fun是在fun.c中实现的,但在main.c文件中用,

应该是调用main.c中的base()还是fun.c中的base()呢?其实,链接器自己都搞不清清楚了,所以报错了!


这里我突然想到一个问题:如在main中调用strlen(),但是编译的时侯,仅仅编译test.c,$gcc test.c即可!不需要编译strlen所在的.c文件吗?这个该怎么解释呢?

是不是这样的,这些标准函数已经编译成了动态链接库,程序编译后,直接链接就可以!但是,是通过什么样的方法找到对应的动态链接库文件呢?

对比自己写的函数API怎么才能像系统的strlen()一样呢?直接编译调用函数的那个文件?(待补充。欢迎赐教....)


对于上面的程序,如果这样编译

$gcc -c fun.c

$gcc -o main main.c

则报没有定义fun的错误;

/tmp/ccRYqwWl.o: In function `main':
main.c:(.text+0xc): undefined reference to `fun'        //未定义引用到‘fun’,因为fun.h中的fun();仅是声明!
collect2: error: ld returned 1 exit status,


---------------------------------------------------------------------------------------

为什么重定义呢?因为#include是预处理部分,在编译之前由预处理程序在这个部分复制头文件的内容过来。所以在编译时候,main.o和fun.o文件都有base()函数的定义。那么链接程序就不知道链接那个定义好了(二义性啊)

如何解决呢,为了实现“声明和实现分开”这个目标最好就是把这个base函数的函数体移到源文件里面。如果由于某种原因真的要放在头文件中...也可以。

static声明就可以了,静态函数的作用域是文件,而不是全局。比如,上面的例子将头文件里面的void base(){}改成static void base(){},那就OK。








阅读更多
个人分类: C/C++
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭