问题描述
某个文件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检查出来函数不一致了。