如果一个函数在多个只允许本源文件中所有函数内都需要使用该怎么办

9.4.1& UNIX
首先假定UNIX系统下安装了标准的UNIX C 编译器cc。文件file1.c和file2.c中包含有C的函数。下面的命令将把这两个文件编译在一起并生成可执行文件a.
cc file1.c file2.c
另外还将生成两个目标文件file1.o和file2.o。如果随后只更改了file1.c而没有改变file2.c,可以使用以下命令编译第一个文件并将其链接到第二个文件的目标代码:
cc file1.c file2.o
在UNIX系统下有一个make命令可以自动管理多文件程序,本处不对此深入讨论。
9.4.2& LINUX
首先假定Linux系统下安装了GNU C 编译器gcc。文件file1.c和file2.c中包含有C的函数。下面的命令将把这两个文件编译在一起并生成可执行文件a.
gcc file1.c file2.c
另外还将生成两个目标文件file1.o和file2.o。如果随后只更改了file1.c而没有改变file2.c,可以使用以下命令编译第一个文件并将其链接到第二个文件的目标代码:
gcc file1.c file2.o
9.4.3& DOS命令行编译器
大多数DOS命令行编译器的工作机制同UNIX系统下的cc命令类似。一个不同之处在于DOS系统下目标文件的扩展名是.obj而不是.o。而且有些编译器并不生成目标代码文件,而是生成汇编语言或其他特殊代码的中间文件。
9.4.4& windows和Macintosh编译器
Windows和Macintosh系统下的编译器是面向工程的。工作(project)描述了一个特定的程序所使用的资源。这此资源中包括源代码文件。使用这种编译器运行单文件程序时,必须创建工程。而对于多文件程序 ,需要使用一个菜单命令将源代码文件加入到一个工程之中。而且工程必须包含所有的源代码文件(扩展名为.c的文件)。但是,头文件不能包含在工程之中。因为工程只管理所使用的源代码文件,而使用哪些头文件需要由源代码文件中的#include指令确定。
9.4.5& 头文件的使用
如果把main()函数放在第一个文件中而把自定义函数放在第二个文件中实现,那么第一个文件仍要使用函数原型。如果把函数原型放在一个头文件中,就不必每次使用这些函数时输入其原型声明了。这也正是C标准库的做法,比如把输入/输出函数的原型声明放在stdio.h中,把数学函数的原型声明放在math.h中。对于包含自定义函数的文件也可以这么做。
编写程序的过程中,需要经常使用C的预处理器定义常量。而定义的常量只能用于包含相应#define语句的文件。如果程序中的函数分别放在不同的文件之中,那么就必须使定义常量的#define指令对每个文件都可用。而直接在每个文件中键入该指令的方法既耗时又容易出错,同时也会带来一个维护上的问题:即如果修改一个使用#define定义的数值,那么必须在每一个源代码文件中对其进行修改。比较好的解决方法是把所有的#define指令放在一个头文件中,然后在每个源代码文件中使用#include语句引用该头文件。
总之,把函数原型和常量定义放在一个头文件中是一个很好的编程习惯。
我们考虑这样一个例子,假设需要管理4个连锁的旅馆,每一个旅馆都有不同的收费标准,但是对于一个特定的旅馆,其中的所有房间都符合同一种收费标准。对于预定住宿时间超过一天的人来说,第2天的收费是第一天的95%,而第3天的收费则是第2天的95%,等等。我们需要这样一个程序,即对于指定的旅馆和总的住宿天数可以计算出收费总额。同时,程序中要实现一个菜单,从而允许用户反复进行数据输入直到选择退出。
程序清单9.9、9.10以及9.11列出了上述程序的源代码。第一个程序清单包含了main()函数,在mian()函数中可以看到整个程序的组织结构。第二个程序清单包含所使用的函数,而且我们假设这些函数放在一个单独的文件中。最后,程序清单9.11列出了一个头文件,其中包含了程序的所有源文件使用的自定义常量和函数原型。前面讲过,在UNIX和DOS环境下,指令#include "hotels.h"中的双引号表示被包含的文件位于当前目录下(该目录一般包含源代码)。
程序清单& 9.9& usehotel.c控制模块
/*usehotel.c
--旅馆房间收费程序*/
/*与程序清单9.10一起编译*/
#include &stdio.h&
#include "hotel.h"
/*定义常量、函数声明*/
int main(void)
double hotel_
while((code=menu())!=QUIT)
switch (code)
case 1:hotel_rate = HOTEL1;
case 2:hotel_rate = HOTEL2;
case 3:hotel_rate = HOTEL3;
case 4:hotel_rate = HOTEL4;
default:hotel_rate = 0.0;
printf("Oops!\n");
nights = getnights();
showprice(hotel_rate,nights);
printf("Thank you and goodbye. ");
程序清单& 9.10& hotel.c函数支持模块
/*hotel.c --旅馆管理函数*/
#include &stdio.h&
#include "hotel.h"
int menu(void)
printf("\n%s$s\n",STARS,STARS);
printf("Enter the number of the desired hotel: \n");
printf("1) Fairfield Arms
2) Hotel Olympic\n");
printf("3) Chertworthy Plaza
4) The Stockton\n");
printf("5) quit\n");
printf("%s%s\n",STARS,STARS);
while((status=scanf("%d",&code))!=1 || (code&1 || code&5))
if(status != 1)
scanf("%*s");
/*在scanf()中,把*放在%和说明符之间,它使用函数跳过相应的输入项目*/
printf("Enter an integer from 1 to 5,please.\n");
int getnights(void)
printf("How many nights are needed? ");
while(scanf("%d",&nights)!=1)
scanf("%*s");
printf("Please enter an integer,such as 2.\n");
void showprice(double rate,int nights)
double total = 0.0;
double factor = 1.0;
for (n=1;n&=n++,factor *= DISCOUNT)
total += rate*
printf("The total cost will be $%0.2f.\n",total);
程序清单& 9.11& hotel.h头文件
--hotel.c中的常量定义和函数声明*/
#define QUIT 5
#define HOTEL1 80.00
#define HOTEL2 125.00
#define HOTEL3 155.00
#define HOTEL4 200.00
#define DISCOUNT 0.95
#define STARS "******************************"
//给出选项列表
int menu(void);
//返回预定的天数
int getnights(void);
//按饭店的星级和预定的天数计算价格并显示出来
void showprice(double,int);
顺便提一下,程序中有几处很有特色。比如,函数menu()和getnights()通过检测scanf()的返回值来跳过输入的非数字数据,并且调用scanf("%*s")来跳至下一空白字符。请注意menu()中的以下代码如何检查出非数字的输入和超出范围的数据:
while((status=scanf("%d",&code))!=1 || (code&1 || code&5))
这段代码运用了C的两个运算规则:逻辑表达式从左向右运算;并且一旦结果明显为假,运算会立即停止。在本例中,只有确定scanf()已经成功读取了一个整形数值后, 变量code的数值才会被检测。
用函数分别实现各个独立的功能需要使用这种精练的语句。当然第一次编写menu()和getnights()时可能只使用了简单的scanf()函数而没有数据检查功能。然后,就可以根据基本程序的运行情况对每个模块进行改进。
阅读排行榜温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
fatal error LNK1169: 找到一个或多个多重定义的符号之后,我尝试吧其中一个源文件里的int main()删去,在另一个源文件里加入#include “另一个文件名.cpp” ,还是编译失败报错情况:error LNK2005: "void __cdecl asd(void)" (?asd@@YAXXZ) 已经在 sio.obj 中定义fatal error LNK1169: 找到一个或多个多重定义的符号于是我写了一个头文件包含了void asd()的声明,同时有int main()的文件中包含了改头文件,编译成功,运行正常于是我在ubuntu下新建了一个文件夹touch,里面有三个文件a.c b.c makefilea.c里为 int main () {printf("a\n");}&b.c里为&int main () {printf("b\n");}&makefile里第一句为test:a.o b.o cc -o test a.o b.omake编译,仍然是失败,报错为b.o: In function 'main':b.c:(.text+0x0): multiple definition of 'main'a.o:a.c:(text+0x0): first defined herecollect2:ld 返回 1之后,我把其中一个main函数改为普通函数,通过另一个文件调用即a.c 里改为void kain () {printf("a\n");}&b.c里改为&int main () {printf("b\n");kain();}makefile不变make编译成功考虑到若是c++会不会不一样,我把makefile里的cc改成g++,结果make编译时发生错误,b.c编译时会发现错误:“kain”在此作用域中尚未声明于是我写了一个ab.h里包含了void kain()的声明,在a.c中包含了头文件ab.h,同时改写makefile,相当于b.c是对ab.h里的kain()的定义make编译后成功个人总结:对于C:Linux下可以同过编写makefile使先分别编译同一项目下的不同源文件,再把不同文件连接起来&& & & & & & & & & 对于C++:无论VS2010还是Linux环境下要连接两个或多个源文件,需要通过头文件声明函数,不含有main函数的源文件相当于对头文件里声明的定义,含有main函数的源文件需要包括该头文件& & & & & & & & & 无论是linux下还是windows下,无论c还是c++都不允许一个工程下含有两个或以上main函数
阅读(7651)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'关于一个工程下多个源文件以及main函数',
blogAbstract:'今天经测试,同一工程下的两个源文件同时存在int main()编译时是会发生错误的(测试环境:win7 VS2010)报错情况:fatal error LNK1169: 找到一个或多个多重定义的符号之后,我尝试吧其中一个源文件里的int main()删去,在另一个源文件里加入#include “另一个文件名.cpp” ,还是编译失败报错情况:error LNK2005: \"void __cdecl asd(void)\" (?asd@@YAXXZ) 已经在 sio.obj 中定义fatal error LNK1169: 找到一个或多个多重定义的符号于是我写了一个头文件包含了void asd()的声明,同时有int main()的文件中包含了改头文件,编译成功,运行正常',
blogTag:'多个源文件,main',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:9,
publishTime:7,
permalink:'blog/static/',
commentCount:4,
mainCommentCount:3,
recommendCount:2,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}C/C++:多个.cpp文件包含同一个.h头文件定义方法
本文解决multiple definition of `XX'的错误。【出于反爬虫的目的,你不是在https://blog.csdn.net/zhanh1218上看到的,肯定不是最新最全的。】
关于头文件的定义中,请一定加上以下代码(此为头文件保护符):
#ifndef PERSON_H_
#define PERSON_H_
// 你的代码块
#endif /* PERSON_H_ */其中PERSON_H_为保护符的名字,一般建议与类名保持一致!例子中我的类名为Person.h。
每当编译器遇到#include时,都要去编译相关代码块,但是编译器不知道是不是已经编译过了,如果编译过了还去编译,那是不是等于代码块写了两次呢?所以,需要有不重复编译的机制,而这个机制正式以上代码。
具体实现为:#ifdef当且仅当变量已定义时为真,#ifndef当且仅当变量未定义时为真。一旦检测结果为真,则执行后续操作直至遇到#endif。
也就是说:如果首次include "Person.h",PERSON_H_是没有定义,此时,编译器会define这个保护符,并执行代码块的编译!直到遇到#endif。下次遇到这个保护符,就不会执行代码块的编译了。这样的机制保证了不会重复编译。
实际使用中,我发现,单个cpp文件中多次include 同一个.h头文件或者头文件中多次include某个头文件,不会有问题。但是,多个cpp文件都include 同一个.h头文件时,这样会出问题。问题是类外定义的非static及非inline函数还是会报multiple
definition of `XX'的错误。【也就是说:#define的作用域只是单个.cpp,而不是全局所有的.cpp文件】
最终解决方法是:只在头文件定义类的申明和类的主体定义(也就是{}内的内容),在一个同名的.cpp文件里定义类外函数的实现!问题完美解决。所以,就算是大神写的书,书上也不完全是对的,或者表述的全部都清楚。
那么为什么头文件可以定义成以下形式呢?而不是只申明,不定义类体呢?
类的定义,只是告诉编译器,类的数据格式是如何的,实例话后对象该占多大空间。
类的定义也不产生目标代码。因此它和普通变量的声明唯一的区别是不能在同一编译单元内出现多次。
另一个原因就是,类可以在多个.cpp文件里重定义,变量却不行,除非用extern或者staic修饰的变量。
至于普通变量:允许static型的变量的定义;允许extern申明(不能定义!);直接申明例如int
是不行的,也是多次重新定义。
extern表明该变量在别的地方已经定义过了,在这里要使用那个变量;static
表示静态的变量,分配内存的时候,存储在静态区,不存储在栈上面。【一篇不错的Blog:点击打开链接】
下面是代码示例,此实例部分为C++ Primer练习题。【反爬虫,第二天更新代码!】
/*********************************************************************
* file_name: vector_test.cpp
Created on: 日 下午3:34:23
Author: The_Third_Wave, Blog: https://blog.csdn.net/zhanh1218
* Last modified: 日 下午3:34:23
*********************************************************************/
#include "Headers/Person.h"
int main()
std::vector per = {{"The_Third_Wave", 100, "Blog: https://blog.csdn.net/zhanh1218"}}; // 类初始化+vector初始化,所以{{}, {}}必须的
for (auto &p: per)
print(std::cout, p);
}/*********************************************************************
* file_name: ddqdq.cpp
Created on: 日 下午10:28:42
Author: The_Third_Wave, Blog: https://blog.csdn.net/zhanh1218
* Last modified: 日 下午10:28:42
*********************************************************************/
#include "Headers/Person.h"
/*********************************************************************
* file_name: Person.h
Created on: 日 下午11:47:08
Author: The_Third_Wave, Blog: https://blog.csdn.net/zhanh1218
* Last modified: 日 下午11:47:08
*********************************************************************/
#ifndef PERSON_H_
#define PERSON_H_
/*****************************BEGIN***********************************/
class Person
friend istream &read(istream &is, Person &item);
friend ostream &print(ostream &os, const Person &item);
Person() =
Person(const string &n, unsigned int a, string add):
name(n), age(a), address(add) { }
Person(istream &);
string Name() const {}
unsigned int Age() const {}
string Address() const {}
string name = "";
unsigned int age = 1;
string address = "";
Person::Person(istream &is)
read(is, *this);
/******************************END************************************/
#endif /* PERSON_H_ *//*********************************************************************
* file_name: Person.cpp
Created on: 日 下午10:55:32
Author: The_Third_Wave, Blog: https://blog.csdn.net/zhanh1218
* Last modified: 日 下午10:55:32
*********************************************************************/
#include "Person.h"
istream &read(istream &is, Person &item)
is >> item.name >> item.age >> item.
ostream &print(ostream &os, const Person &item)
os << item.name << " " << item.age << " " << item.address <<
还有不懂的请留言。
本文由@The_Third_Wave(Blog地址:https://blog.csdn.net/zhanh1218)原创。还有未涉及的,会不定期更新,有错误请指正。
如果你看到这篇博文时发现没有不完整,那是我为防止爬虫先发布一半的原因,请看原作者Blog。
如果这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!如果您一定要转载,请带上后缀和本文地址。扫一扫体验手机阅读
<span type="1" blog_id="2146951" userid='
1篇文章,91人气,0粉丝
高并发架构之路
¥51.00136人订阅
新西兰资深网工运维之道
¥51.00436人订阅
前百度高级工程师的架构高可用实战
¥51.00236人订阅
<span type="1" blog_id="2146951" userid='百度题库旨在为考生提供高效的智能备考服务,全面覆盖中小学财会类、建筑工程、职业资格、医卫类、计算机类等领域。拥有优质丰富的学习资料和备考全阶段的高效服务,助您不断前行!
京ICP证号&&
京网文[3号&&
Copyright (C) 2018 Baidu}

我要回帖

更多关于 只允许本源文件中所有函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信