C编程-extern使用问题

Posted by 周思进 on January 25, 2021

日常工作开发经常会存在不规范使用 extern 的情况,比如下面示例代码

//fun.c
int fun(int a)
{
    return a+1;
}


//main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    int ret = 0;
    ret = fun(1);
    printf("ret:%d\n", ret);
    return 0;
}

编译选项建议默认放开 -Wall ,否则可能编译链接过程并不会报错,执行也没问题。

image

对于编译时提示的编译告警都应该进行处理解决,这样大部分的传参类型不匹配都能解决掉,避免可能存在的安全问题。

如上图所示,在进行编译链接的时候,报了如下错误:

main.c:8:11: warning: implicit declaration of function ‘fun’ is invalid in C99 [-Wimplicit-function-declaration] ret = fun(1);

而很多时候,开发人员基本会为了方便,直接在 main.c 文件进行 extern 引用声明

extern int fun(int a);

通过该方式进行编译链接就不会存在告警了,但这是会存在风险的。


如果 fun 接口的维护人员修改了该接口实现,比如增加了入参个数变成下面这样了

int fun(int a, int b)
{
    return a+b+1;
}

但并没有去修改 extern 处的函数声明,你会发现程序编译链接并不会出现任何告警,但执行结果就和之前完全不一样了,更有可能,修改了函数的实现后会直接导致程序崩溃。

正确的做法 fun.c 需要新增外部可包含的头文件声明 fun.h,而 main.c 要调用 fun.c 里的函数接口,则需要包含 fun.h 头文件。

这里还有一点需要注意,即 fun.c 也同样需要包含 fun.h 头文件,否则如果开发人员只修改了 fun.c 里的函数声明,但因为没有包含 fun.h 头文件,那么程序编译链接仍旧是不会报错的,只有 fun.c 也同样包含 fun.h 才会发生报错。

所以最终实现应该如下:

//fun.h
int fun(int a, int b);

//fun.c
#include <stdio.h>
#include "fun.h"

int fun(int a, int b)
{
    return a+b+1;
}

//main.c
#include <stdio.h>
#include "fun.h"

int main(int argc, char const *argv[])
{
    int ret = 0;
    ret = fun(1, 2);
    printf("ret:%d\n", ret);
    return 0;
}

只有这样当开发人员修改了 fun.c 里 fun 函数的接口声明时,各引用的地方都会报错被发现。