)
库的使用与.h文件的创建关系一、完全可以不写#include xxx.h程序能编译运行前提只用普通函数不涉及结构体、宏、自定义类型C 老标准会自动给未声明函数做隐式声明默认返回int参数任意。你只把.c打包成静态 / 动态库主函数里直接裸写调用hello();编译链接带上库就能生成可执行文件。缺点非常致命函数参数写错、传参类型不对、传多传少编译器不会报错运行随机崩溃函数实际返回值不是 int会发生数据截断一旦库里有结构体、枚举、#define 宏主程序完全无法识别代码写不了。二、规范写法必须新建一个 .h 头文件主程序#include标准流程企业 / 作业标准写法库源文件mylib.c放函数实现#include stdio.h void show(int a) { printf(%d\n,a); }新建头文件mylib.h专门放对外声明#ifndef MYLIB_H #define MYLIB_H void show(int a); // 只写声明不写实现 #endif把 mylib.c 编译打包成静态库 libmylib.a主程序 main.c 里 #include mylib.h#include mylib.h int main() { show(666); return 0; }这么做的意义编译阶段编译器检查参数数量、类型、返回值完全匹配错了直接报错结构体、宏、typedef 全部放在头文件调用方才能正常使用别人使用你的库时只需要拿.h.a/.so不用看你的.c源码。三、折中方案不建 .h直接在 main.c 手写函数声明不想新建文件可以在 main 最上方手动声明函数效果等价于 include 头文件// 手动声明库里面的函数 void show(int a); int main() { show(123); return 0; }适合函数极少的临时测试项目大了绝对不推荐不方便维护。最终结论懒人测试啥头文件都不用直接调用能跑但隐患极大正规开发一定要配套.h放声明主程序#include头文件不参与库的编译打包库只由.c生成.h只给调用方使用。额外知识点打包静态库 / 动态库的时候从头到尾不需要头文件参与。.h不属于库文件内容只是给调用者看的接口说明书。四、那你创建函数的.c文件要不要 带#include xxx.h呢1、先回答第一个点打包静态库只打包 add.c不带.h发给别人本身确实没有强制校验静态库libxxx.a里面只有编译后的机器码 函数符号名。 头文件.h不会被打进库里面库文件完全不知道外面有没有头文件、头文件叫什么。 所以理论上 我只发你libadd.a你自己随便新建一个test.h手写一行int add(int x,int y);只要签名对得上#include test.h就能正常调用。 文件名、头文件名字不需要和原作者的 add.h 一模一样。2、那原作者 add.c 里为什么一定要#include add.h这个校验是给自己编译库的时候用的不是给使用者用的。场景举例我写 add.hint add(int a,int b);我写 add.c 手误写成int add(int a){return a1;}如果 add.c 开头写了#include add.h编译gcc -c add.c直接报错声明和定义参数不匹配我当场改错。如果不加这行 编译 add.c 毫无报错顺利打包成库发给你。 你拿着库随便写个头文件调用编译时才发现参数对不上甚至运行崩掉。简单说#include add.h是库作者自查防止自己写实现写错 不是用来约束后续使用者的。3、使用者可以自定义头文件吗完全可以原项目add.h add.c → 打包 libadd.a 你拿到库之后完全可以不使用原 add.h自己新建一个叫my_api.h#ifndef MY_API_H #define MY_API_H int add(int m, int n); #endifmain.c 包含#include my_api.h照样正常链接使用库没有任何强制绑定关系。4、行业里为什么还要配套给原有的.h库里不止一个函数还有结构体、宏、枚举、类型重定义 这些东西只存在于.h里库二进制不带这些信息。 你不拿作者提供的头文件根本不知道结构体怎么定义没法传参。方便不用使用者手动挨个抄写所有函数声明直接拿头文件即可。约定俗成接口文件同名便于项目管理。5、极简总结打包库 ≠ 打包头文件库内无任何头文件信息add.c 引入自身 add.h作者自检防写错和第三方使用者无关使用者可以自创任意名称头文件只要函数声明签名一致就能调用正式交付库一定会附带原版.h是为了降低使用成本不是程序强制要求。补充一句最容易混淆的边界编译库本身需要.c 作者自己的.h做自检别人链接使用库只需要.a 任意一份正确声明的.h文件名无要求。