extern函数问题


问题描述

某个文件extern声明一个函数并使用,在后续开发中该函数被修改,入参增加了,但是因为前述文件并没有更新extern声明,也没有修改调用,导致编译和链接时候没有报错,但是运行时出现段错误

测试分析

在文件A.c实现函数

#include <stdio.h>
int funC(void)
{
    return 15;
}

在文件B.c 内

#include <stdio.h>
extern int funC(int a);

int main(void)
{
    int ret = funC(1);
    printf("%d\n",ret);
    return 0;
}

编译后发现没有报错,逐步增加编译告警级别和参数,增加-Wmissing-declarations时候需要在A.c 先声明一下,其余参数没有造成影响

-std=c11 -W -Wall -Werror -Wextra -Wstrict-prototypes -Werror=implicit-function-declaration -Wnested-externs -Wmissing-prototypes -Wmissing-declarations  -Wimplicit-function-declaration

完整的options见页面 https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html
上述gcc options中,-W -Wall -Werror -Wextra 通常是用来调高编译告警级别的

-Wall包含

-Waddress
-Warray-bounds=1 (only with -O2)
-Wbool-compare
-Wbool-operation
-Wc++11-compat -Wc++14-compat
-Wcatch-value (C++ and Objective-C++ only)
-Wchar-subscripts
-Wcomment
-Wduplicate-decl-specifier (C and Objective-C only)
-Wenum-compare (in C/ObjC; this is on by default in C++)
-Wformat
-Wint-in-bool-context
-Wimplicit (C and Objective-C only)
-Wimplicit-int (C and Objective-C only)
-Wimplicit-function-declaration (C and Objective-C only)
-Winit-self (only for C++)
-Wlogical-not-parentheses
-Wmain (only for C/ObjC and unless -ffreestanding)
-Wmaybe-uninitialized
-Wmemset-elt-size
-Wmemset-transposed-args
-Wmisleading-indentation (only for C/C++)
-Wmissing-attributes
-Wmissing-braces (only for C/ObjC)
-Wmultistatement-macros
-Wnarrowing (only for C++)
-Wnonnull
-Wnonnull-compare
-Wopenmp-simd
-Wparentheses
-Wpessimizing-move (only for C++)
-Wpointer-sign
-Wreorder
-Wrestrict
-Wreturn-type
-Wsequence-point
-Wsign-compare (only in C++)
-Wsizeof-pointer-div
-Wsizeof-pointer-memaccess
-Wstrict-aliasing
-Wstrict-overflow=1
-Wswitch
-Wtautological-compare
-Wtrigraphs
-Wuninitialized
-Wunknown-pragmas
-Wunused-function
-Wunused-label
-Wunused-value
-Wunused-variable
-Wvolatile-register-var

-Wextra包含

-Wclobbered
-Wcast-function-type
-Wdeprecated-copy (C++ only)
-Wempty-body
-Wignored-qualifiers
-Wimplicit-fallthrough=3
-Wmissing-field-initializers
-Wmissing-parameter-type (C only)
-Wold-style-declaration (C only)
-Woverride-init -Wsign-compare (C only)
-Wredundant-move (only for C++)
-Wtype-limits -Wuninitialized
-Wshift-negative-value (in C++03 and in C99 and newer)
-Wunused-parameter (only with -Wunused or -Wall)
-Wunused-but-set-parameter (only with -Wunused or -Wall)

开启了上面的option却仍然不能在编译或者链接时候检查出来上面的函数声明不一致的问题。

因为编译的时候,只检查每个C文件内部是否满足规则,包含其头文件引用;

链接的时候,如果extern函数没有定义是可以检查出来的,但是定义了,extern声明的入参不一致则无法检查出来。链接只检查函数符号表,而所有入参实际上是入栈操作。

也有说法是考虑到C语言允许可变长入参,比如printf等函数,所以入参个数不检查。

但是如问题中出现的现象,参数个数或者原型变化,会在执行时发生未定义的操作,引起程序崩溃,

所以最好还是在头文件中声明函数,定义个使用的文件直接引用头文件,就能够利用gcc检查出来函数不一致了。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 引子 gcc and g++分别是gnu的c & c++编译器。gcc/g++在执行编译工作的时候,总共需要4步1...
    Alfie20阅读 3,060评论 2 0
  • #pragma clang diagnostic push #pragma clang diagnostic ig...
    俆先生阅读 1,959评论 0 0
  • 参考链接今天看 MJRefresh 源码有一段忽略获的代码,借机整理下相关内容 #pragma在本质上是声明,常用...
    wpf_register阅读 6,924评论 0 2
  • 在iOS开发过程中, 我们可能会碰到一些系统方法弃用, weak、循环引用、不能执行之类的警告。 有代码洁癖的孩子...
    梦翔_d674阅读 2,515评论 0 3
  • 在iOS开发过程中, 我们可能会碰到一些系统方法弃用, weak、循环引用、不能执行之类的警告。 有代码洁癖的孩子...
    磁针石阅读 11,537评论 0 16