前言
(1)如果有嵌入式企业需要招聘湖南区域日常实习生,任何区域的暑假Linux驱动实习岗位,可C站直接私聊,或者邮件:zhangyixu02@gmail.com,此消息至2025年1月1日前均有效
(2)今天,在交流群看到一个有意思的问题,在此分享出来。
(3)注意,本文需要一定的汇编基础和gcc编译流程基础。
问题
(1)群友问:下面这个代码为啥能够编译通过?在
diag_application.c
中调用WriteDid_Port()
函数只传递了3个参数。但是在diag_did.c
文件中定义WriteDid_Port()
函数的时候,需要传递4个参数啊。
(2)这里需要注意一点,diag_application.c
文件中,没有包含diag_did.h
文件。
分析
为什么能够编译通过
(1)首先,有同学肯定会问了,
diag_application.c
文件中,没有包含diag_did.h
文件,这么明显的错误,怎么会编译通过呢?
(2)这个很好理解,如果diag_did.h
文件里面只有extern
的函数声明,那么你没有包含diag_did.h
文件只会报警告,而不是报错误。所以是可以编译通过的。
(3)同时这里很可能是写脚本的同事,设置了无视所有警告的编译选项,因此最终编译结果是0报错,0警告的完美状态。
(4)如果没有设置无视警告的编译选项,一定会报隐式声明的警告。隐式声明作为C语言的一个大坑,一定要注意。
<1>在C标准中,所有函数都是全局可见的。如果没有extern
,所有文件也都可以访问此函数。但是为什么需要extern
,其实是为了传参的时候知道应该传递什么参数,函数会返回什么参数,如果没有extern编译器会做隐式申明。有没有extern
,生成的汇编会略有不同(不同点就是进入函数压栈的时候,需要存几个,退出的时候是否需要返回数据)。但是都是会申明此函数来自外部。
<2>因为这里的函数并没有static
特性,所以说外部可以访问。那么在链接阶段就会将这两个.o
文件中的WriteDid_Port()
函数链接在一起。
<3>而汇编不一样,汇编代码自带static
特性,没有.global
指令,外部永远不可见。
这样做有什么隐患
(1)我们不清楚隐式声明最终声明成什么样子,这里编译器很可能会根据你怎么写的,就怎样隐式什么,这样会导致运行时候最后传参是未知值,跑的时候出现莫名其妙的问题。
参考
(1)万恶之源:C语言中的隐式函数声明
(2)Linux-GCC介绍+入门级Makefile使用