QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1070|回复: 7

一个很弱的问题:.h文件怎么用?

[复制链接]
发表于 2004-11-11 15:47:35 | 显示全部楼层 |阅读模式
不好意思,虽然学C++已有两年多时间,可这个问题我还是没搞清楚.
现在在linux下写C程序更是被搞晕了~~~

比如我现在想写一些函数,那么照书上说我应该在.h文件中(比如是test.h)写函数申明以及宏定义等东西,然后在test.c文件中写函数体.
但是如果我在其它代码(如abc.c)中要用到这几个函数,那么除了要在abc.c中写
#include "test.h",
还要在gcc后面加上test.c才能顺利编译,
gcc abc.c test.c
否则就找不到函数体...

我觉得这样也太麻烦了,就干脆把函数体什么的直接写在test.h中,不去写test.c文件,然后gcc abc.c就能顺利编译. 这样不是很方便吗?会出什么问题吗?
发表于 2004-11-11 16:42:48 | 显示全部楼层
你的问题在于并不了解编译的内部流程,而且可能你也用过java,受了java的影响。

gcc的编译过程是
1 预编译器把源程序和#include的内容合并成一个文件。
2 c编译器把1做出的文件编译成汇编程序。
3 汇编编译器把2做出的汇编程序做成二进制对象文件。
4  对每一个源程序执行上面1,2,3的过程。
5 连接器把4做出来的所有二进制对象文件连结成特定格式的可执行文件。

你的问题就在流程2里,h文件的作用就是说明别的地方有什么,这样3在制作二进制文件时就会为外部函数留下一个调用符号,以便5连接时用。

所有的公有函数,变量名在流程3执行后会登录在二进制对象文件的符号表里,帮助5连接时用。而在连结时,两个二进制对象文件的符号表里不能有重名的对象,否则连结器不知道该连结谁。

最后如果你把函数实现写在h文件里,那么最终就会在不同的二进制对象文件里生成相同的符号(考虑1的动作)而连结失败。这时候你也许可以在函数前追加static修饰(对static修饰过的函数或变量3的动作不会在符号表里登录),结果是所有的二进制对象文件都有一份实现,最终连结出来的可执行文件尺寸就会随着工程量的增加以几何级增长。
回复

使用道具 举报

发表于 2004-11-12 09:08:20 | 显示全部楼层
如果你自己写个Makefile,你就不这么认为了
回复

使用道具 举报

发表于 2004-11-12 09:35:48 | 显示全部楼层
  
回复

使用道具 举报

发表于 2004-11-12 11:57:45 | 显示全部楼层
在源文件中加入
#include "test.c"
然后
gcc abc
就可以了
回复

使用道具 举报

 楼主| 发表于 2004-11-12 12:13:04 | 显示全部楼层
谢谢2楼的回答!
你说的不错,我现在主要用java,但我先学的是C++,那5个步骤还是大体了解的.

[quote:286d4bdbae="kakuyou"]如果你把函数实现写在h文件里,那么最终就会在不同的二进制对象文件里生成相同的符号(考虑1的动作)而连结失败。这时候你也许可以在函数前追加static修饰(对static修饰过的函数或变量3的动作不会在符号表里登录),结果是所有的二进制对象文件都有一份实现,最终连结出来的可执行文件尺寸就会随着工程量的增加以几何级增长。[/quote]
这一段倒确实没仔细考虑过,但我一般都在头文件加上#ifndef...什么的,比如test.h:
#ifndef TEST_H
#define TEST_H
void test(){
    ......
}
#endif
这样能避免连接失败吧,这么做会有什么问题吗?可执行文件尺寸还会"几何级增长"吗?

另外问一下,你们写程序要调用到自己写的函数会怎么做呢?也需要gcc后面加n个文件吗?
由于现在写的都是小程序,不太想用makefile,觉得那样反而容易让自己搞不清具体编译情况
回复

使用道具 举报

发表于 2004-11-12 12:50:20 | 显示全部楼层
[quote:35ddb2a8ac="w2w2k2k2"]
这一段倒确实没仔细考虑过,但我一般都在头文件加上#ifndef...什么的,比如test.h:
#ifndef TEST_H
#define TEST_H
void test(){
    ......
}
#endif
这样能避免连接失败吧,这么做会有什么问题吗?可执行文件尺寸还会"几何级增长"吗?

另外问一下,你们写程序要调用到自己写的函数会怎么做呢?也需要gcc后面加n个文件吗?
由于现在写的都是小程序,不太想用makefile,觉得那样反而容易让自己搞不清具体编译情况[/quote]

呵呵,几何级数夸张了。

你说的那个宏定义是为了防止我上面说的步骤1重复包含头文件。
我的的最终程序变大是在步骤5。

很明显,你还是没搞明白预编译,编译,连接的区别。

本版精华里有篇make的文章,里面有个通用make文件,一般只需要改一下生成的目标就可以应用在大部分的c,c++工程里。

小程序用gcc把各个文件放在一块无所谓,大工程就绝对应该把各个文件先编译成二进制对象文件,然后再连结成可执行文件,这个可不是用不用make的问题。
回复

使用道具 举报

 楼主| 发表于 2004-11-13 20:24:51 | 显示全部楼层
看了一下那篇make的文章,基本理清思路了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-7 03:28 , Processed in 0.064299 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表