免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3024 | 回复: 7
打印 上一主题 下一主题

[C] 一个司空见惯的问题却突然想不通了:.h和.c文件有何关联? [复制链接]

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-12-17 11:29 |只看该作者 |倒序浏览
问题描述:主程序文件a.c用于实现主要功能;自定义头文件b.h包含a.c所需的头文件的集合,以及自定义函数的原型声明;程序文件c.c包含自定义函数的定义(具体实现);三个文件位于同一目录下

如:
主程序a.c
  1. #include <stdio.h>
  2. #include "b.h"
  3. int main (void)
  4. {
  5.         int a, b;
  6.         a = 8;
  7.         b = 9;
  8.         function_a();
  9.         return 0;
  10. }
复制代码
头文件b.h
  1. void function_a(int, int);
复制代码
自定义函数的实现c.c
  1. void function_a(int x, int y)
  2. {
  3.         printf ("%d\n", x + y);
  4. }
复制代码
请教各位,编译器会根据b.h自动加载c.c吗,还是必须显式手动指定c.c作为命令行参数?三者之间有无必然联系?如果有,是什么关系?

例子很简单,小弟当然可以自己实验看到结果,但烦请各位给出一个理论支撑,多谢。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
2 [报告]
发表于 2013-12-17 11:47 |只看该作者
#include是宏,把.h文件里的代码粘贴进来而已。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
3 [报告]
发表于 2013-12-17 11:49 |只看该作者
回复 2# linux_c_py_php
但是如果.h里面只是函数的原型,但函数的实现是在另一个文件中定义的呢?

   

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
4 [报告]
发表于 2013-12-17 11:54 |只看该作者
自己的实例验证:
主程序文件a.c
  1. #include "b.h"
  2. int main (void)
  3. {
  4.     int a = 8;
  5.     int b = 9;
  6.     sum (a, b);
  7.     return 0;
  8. }
复制代码
头文件b.h
  1. #include <stdio.h>
  2. void sum (int, int);
复制代码
自定义函数的实现c.c
  1. #include "b.h"
  2. void hello (void);
  3. void sum (int x, int y)
  4. {
  5.     printf ("sum is %d\n", x + y);
  6.     hello ();
  7. }

  8. void hello (void)
  9. {
  10.     printf ("Hello!\n");
  11. }
复制代码
编译并执行:
  1. root@c-dev:/test# gcc a.c -o a
  2. /tmp/ccLBu8OH.o: In function `main':
  3. a.c:(.text+0x21): undefined reference to `sum'
  4. collect2: ld returned 1 exit status
  5. root@c-dev:/test# gcc a.c c.c -o a
  6. root@c-dev:/test# a
  7. sum is 17
  8. Hello!
复制代码
结果如此,在编译时需要将自定义函数的实现文件指定为命令行参数

论坛徽章:
2
酉鸡
日期:2013-09-26 11:11:15摩羯座
日期:2014-01-08 13:45:19
5 [报告]
发表于 2013-12-17 12:25 |只看该作者
推荐楼主看一下linker&loader或者《程序员的自我修养》。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
6 [报告]
发表于 2013-12-17 12:59 |只看该作者
回复 5# hejianet
多谢,会的


   

论坛徽章:
0
7 [报告]
发表于 2013-12-17 13:39 |只看该作者
本帖最后由 sqfasd 于 2013-12-17 13:54 编辑
superwujc 发表于 2013-12-17 12:59
回复 5# hejianet
多谢,会的


头文件主要就是把一系列的接口或变量放在一起打包声明,方便引用, 你可以不用头文件,每次都在c文件里使用之前声明一次也行, 但这样做不方便吗不是.
.h文件和.c文件没有必然的联系
头文件的声明是为了类型检查,在编译阶段起作用, 而定义是在链接的阶段起作用

还要注意c++和c的区别, c里面不必声明函数原型,就可以调用一个函数, 但c++为了安全起见必须要在编译阶段找到你调用的函数的原型的声明,否则编译不通过

论坛徽章:
0
8 [报告]
发表于 2013-12-17 13:53 |只看该作者
回复 4# superwujc

如果你不把定义那个函数的源文件作为gcc的输入, 就不会去编译, 链接的时候也就找不到定义
你理所当然的认为编译器会去给你通过头文件推断出函数定义在哪, 事实上编译器不会去做推断, 也没必要
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP