免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: listenxu
打印 上一主题 下一主题

[C] 请教一个编译问题,不用include头文件也可以编译运行成功是怎么回事? [复制链接]

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
21 [报告]
发表于 2014-04-28 09:54 |只看该作者
C在编译时不要求一个函数使用前想要被声明或定义,没有声明/定义过的函数你一样可以调用,编译器会把这个函数作为一个为解决的引用放在object文件里。
连接器/linker负责把所有obj文件和库连接在一起生成可执行文件,此时它会检查所有未解决引用的符号,将其对应到其它obj文件定义的符号表里,如果扫描了所有obj文件都没有发现符号定义,就会报告链接错误。

struct的情况不同,编译器要求所有类型在使用前必须有完整定义,要么你可以去include头文件,要么你在这个源代码里照样重新定义一遍其实也可以,和函数不同,struct不会出现在obj文件的符号表里,所以也不会出现重复定义的问题。

变量又是另外一种情况,编译器要求所有变量在使用前必须定义,或者用extern声明。全局变量会出现在符号表里,所以两个obj文件如果包含重名的全局变量会报错,此时你要确保这个变量只定义了一次,其他obj文件中只能包含一个引用,对应C代码应该用extern声明,表明这个变量是在其他链接单元中定义的。

以上这段文字如果你看懂了,你就不应该再有这方面的问题;如果你没看懂,那就说明你不应该再问这方面的问题,按照@MMMIX的说法,老老实实写程序去吧。

论坛徽章:
0
22 [报告]
发表于 2014-04-28 11:26 |只看该作者
MMMIX 发表于 2014-04-27 21:10
回复 18# listenxu


我遇到问题的解决办法一般是这样;
首先,找方法把问题解决掉,这就包含逐步养成好的编程风格;  其次,再去研究背后的原因; 我想,这两者不矛盾;

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
23 [报告]
发表于 2014-04-28 14:39 |只看该作者
windoze 发表于 2014-04-28 09:54

C在编译时不要求一个函数使用前想要被声明或定义,没有声明/定义过的函数你一样可以调用,编译器会把这个函数作为一个为解决的引用放在object文件里。

没有函数原型的话,编译器会提供一个默认的原型,而这个默认的原型和实际的原型不匹配的话,实际执行可能会给出错误的结果。所以说,要求包含的头文件不包含,纯粹就是自找麻烦。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
24 [报告]
发表于 2014-04-28 14:41 |只看该作者
本帖最后由 MMMIX 于 2014-04-28 14:51 编辑
listenxu 发表于 2014-04-28 11:26
首先,找方法把问题解决掉,这就包含逐步养成好的编程风格;  其次,再去研究背后的原因; 我想,这两者不矛盾;

两个领域你都能 hold 住,那就不矛盾;hold 不住,那就矛盾。

不是所有问题都需要寻根究底,找到它背后的原因。编程的时候,绝大多数时间,你只需要知道什么是正确的做法,然后照做就可以了。也就说,编程时,你应该将自己的精力集中在如何写出正确的代码,而不是编译系统如何处理错误的(不规范的、过时的)代码,或者错误的代码会有什么行为。

拿头文件来说,需要包含的你包含就是了,至于不包含会出现什么现象,编译系统是如何处理的,你关心这些干嘛?

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
25 [报告]
发表于 2014-04-28 14:56 |只看该作者
回复 23# MMMIX

没错,C的原则就是“信任”程序员,它假定你知道你自己在干什么,不会无聊地阻止你做一些看起来很奇怪的事,所谓C的“灵活性”和“自由度”就是指这个。

当然,权力与义务永远是相对应的,作为程序员,你需要证明自己是值得信任的,你要确认自己真的知道自己在干什么,有什么后果。

不幸的是,这事儿还真不像看起来那么简单;更不幸的是,出了问题以后,垃圾程序员一定会把责任推到C身上,然后转去用那些“简单”、“不会出错”、“不需要操心xyz”的语言,同时“告诫”其他一知半解的同行“C是垃圾用C的都是SB快来用ooxx吧”,而这些人中更垃圾的那一群会一遍又一遍的重复这个过程。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
26 [报告]
发表于 2014-04-28 14:59 |只看该作者
windoze 发表于 2014-04-28 14:56
回复 23# MMMIX
没错,C的原则就是“信任”程序员,它假定你知道你自己在干什么,不会无聊地阻止你做一些看起来很奇怪的事,所谓C的“灵活性”和“自由度”就是指这个。

函数原型这个东西,更像是个设计缺陷,而不是灵活和自由的体现。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
27 [报告]
发表于 2014-04-28 15:09 |只看该作者
回复 26# MMMIX

C中的函数原型可以省略的确会造成混乱,但C中原型声明可以和实际定义不一致(话说int f(...)这个原型其实有和没有也没太大区别),当你把C和其他语言的的obj文件链接在一起时,因为无法做到语义上的一一对应,函数原型经常就是这样的一个“概况”而已,起不到约束、检查的作用。

不过我坚决支持编译的时候打开所有警告,没有原型几乎可以肯定是潜在的问题,必须要处理。

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
28 [报告]
发表于 2014-04-28 21:09 |只看该作者
-Wall -Wextra -Werror看看呢

论坛徽章:
1
戌狗
日期:2013-09-27 21:34:55
29 [报告]
发表于 2014-04-29 08:56 |只看该作者
其实你直接写下面的代码也能编译过去的
  1. int main(void)
  2. {
  3. printf("aa");
  4. return 0;
  5. }
复制代码
原因是gcc1)printf是builtin函数,2)链接所有的应用程序时会默认链接标准c库。所以不存在编译失败的问题的。

论坛徽章:
0
30 [报告]
发表于 2014-04-29 10:17 |只看该作者
找了一本编译原理,准备研读一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP