c 工程在 main.c 里面引入其他模块,为什么要引入这个模块的.h 文件呢 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thomaswang
V2EX    问与答

c 工程在 main.c 里面引入其他模块,为什么要引入这个模块的.h 文件呢

  •  
  •   thomaswang 2018-07-27 09:41:55 +08:00 3487 次点击
    这是一个创建于 2713 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最好能讲解的详细点, 多谢

    编译,汇编,链接,可重定位目标文件,符号,符号表

    23 条回复    2018-07-27 21:00:36 +08:00
    ian19znj
        1
    ian19znj  
       2018-07-27 09:53:26 +08:00
    因为需要知道函数,变量以及宏的声明,否则无法调用。
    msg7086
        2
    msg7086  
       2018-07-27 10:22:48 +08:00
    不一定要引入这个模块的.h 文件。

    只要在调用前申明你所用到的文件外的函数、变量还有宏之类的就行了。
    .h 文件只是简化这个过程。
    LuckyKoala
        3
    LuckyKoala  
       2018-07-27 10:40:12 +08:00 via Android
    分离接口和实现,把一个模块的函数,变量声明放到头文件中,具体实现也在同名.c 文件中。

    算是规范吧,你不用头文件也是可以的。

    稍大一点的项目,不同的开发者开发时只负责自己的一部分,但是需要知道其它部分的接口,这个时候就可以查看头文件,但不查看具体实现,避免过分依赖其他模块的实现。
    LuckyKoala
        4
    LuckyKoala  
       2018-07-27 10:46:58 +08:00 via Android
    https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_2.html

    头文件有两个来源,一个是系统提供的接口,还有一个就是用户自定义的。

    使用头文件还有一个好处就是所有一组的声明放在一个头文件中,外部通过 include 头文件来包含内容,需要修改声明的时候,修改一个头文件就行了,对应的引用这个头文件的地方也就应用修改了。
    GPIO
        5
    GPIO  
       2018-07-27 10:47:48 +08:00
    码农翻身之前有篇文章叫《真正的程序员都应该搞清楚编译和链接》,本来想发链接给你的,不过要手机号验证所以作罢,你自己搜一下。
    GeruzoniAnsasu
        6
    GeruzoniAnsasu  
       2018-07-27 10:50:09 +08:00
    其实可以完全不需要头文件

    你试试把需要的函数一个一个手动声明,也是照样可以正常链接的

    但这不是,慢嘛,有能复用的声明干嘛要手动重写一遍?
    thomaswang
        7
    thomaswang  
    OP
       2018-07-27 10:55:26 +08:00
    @LuckyKoala 当 main 这个函数编译的时候,会有个 elf,里面有符号表,里面有一个符号指到其他模块的函数,这里面如何用到别的模块的函数定义,肯定是用了,但是不知道如何用的
    Nitroethane
        8
    Nitroethane  
       2018-07-27 10:59:36 +08:00 via Android
    可以看看“深入理解计算机系统”的“链接”一章,讲得很清楚
    LuckyKoala
        9
    LuckyKoala  
       2018-07-27 11:38:17 +08:00 via Android
    @thomaswang https://en.m.wikipedia.org/wiki/Executable_and_Linkable_Format 这是 wiki 上对 elf 文件格式的介绍,至于如何链接的,你可以找找链接相关的文章看看。

    系统学习的话,楼上提到的《深入理解计算机系统》我也很推荐。
    thomaswang
        10
    thomaswang  
    OP
       2018-07-27 11:38:43 +08:00
    @Nitroethane 看完,你没有发现,不需要引入.h 文件理论上也是可以链接的吗,可是为什么不能呢,引入的作用是什么呢
    yksoft1
        11
    yksoft1  
       2018-07-27 11:48:06 +08:00
    不要.h 里的声明的话 C 编译器不知道这个外部符号的类型(返回值),会默认设为 int 并产生警告。C++里面对于函数以外的符号没有声明,直接就是错误了。
    LuckyKoala
        12
    LuckyKoala  
       2018-07-27 11:50:51 +08:00 via Android
    @thomaswang 为什么不能?你怎么写的?

    不包含头文件的话,自己加上需要的声明就可以了。

    加入 “ int printf(const char *format, ...);” 就可以调用 printf
    usufu
        13
    usufu  
       2018-07-27 11:51:28 +08:00
    程序员的自我修养,这本书看完就知道了。
    GeruzoniAnsasu
        14
    GeruzoniAnsasu  
       2018-07-27 12:05:30 +08:00
    @thomaswang 不是 main 函数编译会有个 elf

    每个.c 都会单独编译成待链接的.o 文件,其中包含本文件定义的强弱符号以及需要链接外部的未定义符号,所有未定义符号都会在链接阶段在所有链接文件中查找,并把对应的调用替换成实际函数地址
    如果期望的某个未定义符号没有找到,一般就会报链接错误,但其实也可以用-undefined dynamic_lookup 强制所有未定义符号在运行期动态查找,标准库中的函数“自带这种定义”(不准确)
    从原理上来说,main 函数其实也可以不用写的,只要 elf 文件头指定入口点就足够,但一般程序必须写 main 的原因是,编译器额外链接了某个.o,叫 /crt?+\.o/ 什么的,这个.o 自带一个 main 符号的引用,所以不写 main 链接这个.o 的时候查找 main 符号失败会像上面说的报链接错误,如果用参数选项控制不去链接额外的这个 crt 入口.o,就不一定需要 main 了,你可以再试试上面说的把 main 符号强制在运行期查找,会发现能链接出可执行文件,但这个程序你不 preload 一个带 main 的 lib 是跑不起来的

    除了强弱符号,还有一类未定义符号,用 nm 查看类型是 U,这类符号会在 elf 被加载时由 ld.so 调用 dlresolve 在动态库中查找
    GeruzoniAnsasu
        15
    GeruzoniAnsasu  
       2018-07-27 12:05:48 +08:00
    ------
    emmmm 最后一段忘记删了
    iceheart
        16
    iceheart  
       2018-07-27 12:45:23 +08:00 via Android
    1.编译过程
    把 .c 源代码编译成机器码,名字是.o
    2.链接过程
    把编译好的各个.o 文件链接成一个可执行文件
    3.
    每个.c 编译过程都是独立互不相关的。也就是说,编译器编译 a.c 的时候编译器不知道有 b.c 存在,编译 b.c 的时候编译器不知道有 a.c 的存在。

    基于以上关系说明,问题来了:
    => a.c 里使用了 b.c 里的一个函数,编译器编译 a.c 的时候不知道有 b.c,咋办?

    编译器采取了一个办法:
    1.使用一种约定,来描述 b.c 里边 a.c 要使用的函数,编译的时候根据约定生成调用指令。
    2.让链接程序根据这些约定把 a.o,b.o 链接成可执行文件。
    这个约定是什么?就是.h 头文件里的结构声明和函数声明。
    thomaswang
        17
    thomaswang  
    OP
       2018-07-27 14:51:01 +08:00
    @iceheart 多谢你来解我疑惑,你是很明白的
    a.c 在编译阶段,不需要约定也是可以,每个.o 文件都有一个符号表,里面有自己的函数符号,也有调用的别人的函数符号,当链接的时候,每个.o 文件到其他所有的.o 文件找自己符号表里面的调外部的函数符号,这样就可以了,是吧
    thomaswang
        18
    thomaswang  
    OP
       2018-07-27 15:10:11 +08:00
    @iceheart

    大佬,你人在上海不,请你吃顿饭啊,顺便和你聊聊技术和人生
    zuoxiaomo
        19
    zuoxiaomo  
       2018-07-27 15:55:03 +08:00
    @thomaswang @iceheart 建议见面后互相给对方起一个名字。。。
    thomaswang
        20
    thomaswang  
    OP
       2018-07-27 17:34:49 +08:00
    @zuoxiaomo 何意
    j5shi
        21
    j5shi  
       2018-07-27 18:31:10 +08:00 via iPhone
    谁说必须 include 那个头文件,其实有很多方法可以绕开
    iceheart
        22
    iceheart  
       2018-07-27 19:54:18 +08:00 via Android
    说头文件是接口约定,只是一种方便理解的说法。这些东西完全可以复制到.c 里边,然后扔掉头文件。
    但是这个约定还是在的,貌似大家都管他叫叫 ABI。
    thomaswang
        23
    thomaswang  
    OP
       2018-07-27 21:00:36 +08:00
    @iceheart 吃饭的事 ok 哇,我就是想找个智者聊聊,我最近在职看机会
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1232 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 17:33 PVG 01:33 LAX 09:33 JFK 12:33
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86