2006年4月10日

声明:本文为转载!文尾有作者联系方式 。
先看一段代码:

 1 #ifndef __INCvxWorksh
 2 #define  __INCvxWorksh 
 3 #ifdef __cplusplus
 4 extern   " C "   {
 5 #endif  
 6 /* */  
 7 #ifdef __cplusplus
 8 }

 9 #endif  
10 #endif  /* __INCvxWorksh */
分析
  显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止该头文件被重复引用。
   那么
1#ifdef __cplusplus
2extern "C" {
3#endif 
4#ifdef __cplusplus
5}

6#endif 
的作用又是什么呢?

extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。

  被extern "C"限定的函数或变量是extern类型的;

  extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:
  extern int a;
仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。

  通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。

  与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

  被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;

未加extern “C”声明时的编译方式

首先看看C++中对类似C的函数是怎样编译的。

  作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。

  _foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。

        同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
     
     未加extern "C"声明时的连接方式
假设在C++中,模块A的头文件如下:
1// 模块A头文件 moduleA.h
2#ifndef MODULE_A_H
3#define MODULE_A_H
4int foo( int x, int y );
5#endif
在模块B中引用该函数:
1// 模块B实现文件 moduleB.cpp
2#include "moduleA.h"
3foo(2,3);
实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!

  加extern "C"声明后的编译和连接方式

  加extern "C"声明后,模块A的头文件变为:
1// 模块A头文件 moduleA.h
2#ifndef MODULE_A_H
3#define MODULE_A_H
4extern "C" int foo( int x, int y );
5#endif
在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:

  (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;

  (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。

  如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。

  所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):
  实现C++与C及其它语言的混合编程。
  明白了C++中extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧。
extern "C"的惯用法

  (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
extern "C"
{
#include 
"cExample.h"
}
而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。

  笔者编写的C++引用C函数例子工程中包含的三个文件的源代码如下:
 1/* c语言头文件:cExample.h */
 2#ifndef C_EXAMPLE_H
 3#define C_EXAMPLE_H
 4extern int add(int x,int y);
 5#endif
 6/* c语言实现文件:cExample.c */
 7#include "cExample.h"
 8int add( int x, int y )
 9{
10return x + y;
11}

12// c++实现文件,调用add:cppFile.cpp
13extern "C" 
14{
15#include "cExample.h"
16}

17int main(int argc, char* argv[])
18{
19add(2,3); 
20return 0;
21}
如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。

  (2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。
  笔者编写的C引用C++函数例子工程中包含的三个文件的源代码如下:
 1//C++头文件 cppExample.h
 2#ifndef CPP_EXAMPLE_H
 3#define CPP_EXAMPLE_H
 4extern "C" int add( int x, int y );
 5#endif
 6//C++实现文件 cppExample.cpp
 7#include "cppExample.h"
 8int add( int x, int y )
 9{
10return x + y;
11}

12/* C实现文件 cFile.c
13/* 这样会编译出错:#include "cExample.h" */

14extern int add( int x, int y );
15int main( int argc, char* argv[] )
16{
17add( 23 ); 
18return 0;
19}
如果深入理解了第3节中所阐述的extern "C"在编译和连接阶段发挥的作用,就能真正理解本节所阐述的从C++引用C函数和C引用C++函数的惯用法。对第4节给出的示例代码,需要特别留意各个细节。

  欢迎与作者联系沟通。联系方式:
  Email: 21cnbao@21cn.com
  MSN: barrysong80@hotmail.com

posted @ 2006-04-10 09:37 heart in the world 阅读(385) | 评论 (0)编辑 收藏


2006年3月9日

制作一份eMule文档,对学习eMule源代码大有帮助!提供交叉引用,
文件名:index.chm 由于博客每次只能上传最多2M,压缩成四分卷,下载后把四部分放到同一个目录下,用压winRar解压即可。
下载地址:
index.part1.rar

index.part2.rar

index.part3.rar

index.part4.rar

有什么问题,请朋友留言!谢!

posted @ 2006-03-09 16:26 heart in the world 阅读(901) | 评论 (8)编辑 收藏


2006年2月26日

前几篇文章也提到过,ACE的所有源文件和头文件都杂乱堆在了ACE_wrappers/ace目录下。这样的代码组织方式给学习ACE带来了很大的困难,很多朋友在看到ace目录下庞大的代码的时候,几乎就失去了学习ACE的信心^_^。因此,我们有必要对ACE的代码进行重新组织,以降低学习曲线。下面,我将给出我对ACE源码的划分方法。其实,我也是刚学习ACE没有多久,对ACE的了解还甚少,所以,我的源码划方式法不一定十分正确,这里共享出来,仅供大家参考。

其实,在ACE的帮助文档里,ACE-subsets.html和ACE-categories.html,这两个文档对指导ACE源码划分起到了很大的作用,否则,我刚刚接触ACE,就想对其进行源码划分,是不可能完成的。ACE-subsets.html,这个文档主要介绍了ACElibrary subsetting。正常情况下,在编译完ACE后,只会产生一个ACE的库。我们可以根据该文档的介绍,简单的修改一下Makefile,就可以对ACE的库进行子集化,我们可以编译出OS、Thread等这样的子库。ACE-categories.html,这个文档对ACE中的代码进行了一些功能上的分类。具体大家可以详细的参考一下这两个文档,这两个文档对学习ACE还是有一定的帮助的。

ACE的源代码目录ace下,我将建立很多子目录,来对ACE的代码进行按功能分类:


ACE_OS:该目录里包含的代码是OS的API的wrapper,也就是ACE的OS适配层;
 包含代码: ARGV.cpp         OS_Memory.cpp
  Argv_Type_Converter.cpp    OS_QoS.cpp
  Base_Thread_Adapter.cpp    OS_String.cpp
  Basic_Types.cpp            OS_TLI.cpp
  Copy_Disabled.cpp          OS_Thread_Adapter.cpp
  Env_Value_T.cpp            Sched_Params.cpp
  Handle_Set.cpp        Template_Instantiations.cpp
  Makefile                   Thread_Hook.cpp
  OS.cpp                     Time_Value.cpp
  OS_Dirent.cpp                
  OS_Errno.cpp                 
  OS_Log_Msg_Attributes.cpp

ACE_Codec:该目录包含的是ACE的各种编码类型的处理代码,目前只包含了BASE64编码的处理;
    包含代码:Codecs.cpp   Makefile


ACE_Connection:该目录包含的是ACE中的Acceptor-Connector框架代码和异步通讯类代码;
  包含代码:Acceptor.cpp           Connector.cpp
   Asynch_Acceptor.cpp             Makefile
   Asynch_Connector.cpp        POSIX_Asynch_IO.cpp
   Asynch_IO.cpp                   Strategies_T.cpp
   Asynch_IO_Impl.cpp              Svc_Handler.cpp
   Asynch_Pseudo_Task.cpp      WIN32_Asynch_IO.cpp
   Cached_Connect_Strategy_T.cpp  
   Caching_Strategies_T.cpp       

ACE_Demux:该目录包含的是ACE中的Reactor和Proactor框架代码;
    包含代码:Dev_Poll_Reactor.cpp     Priority_Reactor.cpp      TP_Reactor.cpp        Event_Handler.cpp         Proactor.cpp              TkReactor.cpp
  Event_Handler_T.cpp       QtReactor.cpp             WFMO_Reactor.cpp
  FlReactor.cpp            Reactor.cpp               WIN32_Proactor.cpp
  Makefile                  SUN_Proactor.cpp          XtReactor.cpp
  Msg_WFMO_Reactor.cpp      Select_Reactor.cpp       
  POSIX_CB_Proactor.cpp     Select_Reactor_Base.cpp  
  POSIX_Proactor.cpp        Select_Reactor_T.cpp

ACE_IPC:该目录包含的是ACE中进程间通讯的一些封装代码:
  包含代码:ATM_Acceptor.cpp             Makefile
  ATM_Addr.cpp                 Pipe.cpp
  ATM_Connector.cpp            SPIPE.cpp
  ATM_Params.cpp               SPIPE_Acceptor.cpp
  ATM_QoS.cpp                  SPIPE_Addr.cpp
  ATM_Stream.cpp               SPIPE_Connector.cpp
  DEV.cpp                      SPIPE_Stream.cpp
  DEV_Addr.cpp                 SV_Message.cpp
  DEV_Connector.cpp            SV_Message_Queue.cpp
  DEV_IO.cpp                   SV_Semaphore_Complex.cpp
  FIFO.cpp                     SV_Semaphore_Simple.cpp
  FIFO_Recv.cpp                SV_Shared_Memory.cpp
  FIFO_Recv_Msg.cpp            Signal.cpp
  FIFO_Send.cpp                TLI.cpp
  FIFO_Send_Msg.cpp            TLI_Acceptor.cpp
  FILE.cpp                     TLI_Connector.cpp
  FILE_Addr.cpp                TLI_Stream.cpp
  FILE_Connector.cpp           TTY_IO.cpp
  FILE_IO.cpp                  Typed_SV_Message.cpp
  IOStream.cpp                 Typed_SV_Message_Queue.cpp
  IOStream_T.cpp               UNIX_Addr.cpp
  IO_SAP.cpp                   UPIPE_Acceptor.cpp
  MEM_Acceptor.cpp             UPIPE_Connector.cpp
  MEM_Addr.cpp                 UPIPE_Stream.cpp
  MEM_Connector.cpp            XTI_ATM_Mcast.cpp
  MEM_IO.cpp                  
  MEM_SAP.cpp                 
  MEM_Stream.cpp

ACE_LIB:该目录将包含ACE编译好的各个子库;

ACE_Logging:该目录包含ACE中的日志处理相关代码;
       包含代码:Dump.cpp                   Log_Msg_UNIX_Syslog.cpp
  Dump_T.cpp                 Log_Record.cpp
  Log_Msg.cpp                Logging_Strategy.cpp
  Log_Msg_Backend.cpp        Makefile
  Log_Msg_Callback.cpp       Trace.cpp
  Log_Msg_IPC.cpp           
  Log_Msg_NT_Event_Log.cpp  

ACE_Memory:该目录包含了ACE内存处理相关代码;
     包含代码:Based_Pointer_Repository.cpp   Obstack.cpp
  Based_Pointer_T.cpp            Obstack_T.cpp
  Makefile                       PI_Malloc.cpp
  Malloc.cpp                     Read_Buffer.cpp
  Malloc_Allocator.cpp           Shared_Memory.cpp
  Malloc_Instantiations.cpp      Shared_Memory_MM.cpp
  Malloc_T.cpp                   Shared_Memory_SV.cpp
  Mem_Map.cpp                   
  Memory_Pool.cpp               
  Obchunk.cpp

ACE_Misc:ACE中一些没有明确功能分类的代码,属于杂项;
   包含代码:CE_Screen_Output.cpp   NT_Service.cpp
  Makefile               gethrtime.cpp

ACE_Nameservices:该目录包含了ACE中名字服务相关代码;
    包含代码: Name_Space.cpp
   Local_Name_Space.cpp           Naming_Context.cpp
   Local_Name_Space_T.cpp         Registry_Name_Space.cpp
   Makefile                       Remote_Name_Space.cpp
   Name_Proxy.cpp                
   Name_Request_Reply.cpp        

ACE_Sockets:该目录包含的是ACE的socket封装代码;
      包含代码:Addr.cpp                       SOCK_CODgram.cpp
  INET_Addr.cpp                  SOCK_Connector.cpp
  IPC_SAP.cpp                    SOCK_Dgram.cpp
  LOCK_SOCK_Acceptor.cpp         SOCK_Dgram_Bcast.cpp
  LSOCK.cpp                      SOCK_Dgram_Mcast.cpp
  LSOCK_Acceptor.cpp             SOCK_IO.cpp
  LSOCK_CODgram.cpp              SOCK_SEQPACK_Acceptor.cpp
  LSOCK_Connector.cpp            SOCK_SEQPACK_Association.cpp
  LSOCK_Dgram.cpp                SOCK_SEQPACK_Connector.cpp
  LSOCK_Stream.cpp               SOCK_Stream.cpp
  Makefile                       Sock_Connect.cpp
  Multihomed_INET_Addr.cpp      
  SOCK.cpp                      
  SOCK_Acceptor.cpp

ACE_Streams:该目录包含了ACE中的Streams和Task框架代码;
      包含代码:CDR_Base.cpp                        Module.cpp
  CDR_Stream.cpp                      Multiplexor.cpp
  Codeset_IBM1047.cpp                 Reactor_Notification_Strategy.cpp
  Codeset_Registry.cpp                Stream.cpp
  Codeset_Registry_db.cpp             Stream_Modules.cpp
  IO_Cntl_Msg.cpp                     Task.cpp
  Makefile                            Task_T.cpp
  Message_Queue.cpp                  
  Message_Queue_T.cpp   

ACE_Svcconf:该目录包含了ACE中的Service Configurator框架代码;
      包含代码:DLL.cpp                    Service_Types.cpp
  DLL_Manager.cpp            Shared_Object.cpp
  Dynamic_Service.cpp        Svc_Conf.l
  Dynamic_Service_Base.cpp   Svc_Conf.y
  Makefile                   Svc_Conf_Lexer_Guard.cpp
  Parse_Node.cpp             Svc_Conf_l.cpp
  Service_Config.cpp         Svc_Conf_y.cpp
  Service_Manager.cpp        XML_Svc_Conf.cpp
  Service_Object.cpp        
  Service_Repository.cpp    
  Service_Templates.cpp

ACE_Threads:该目录包含了ACE中的线程和同步机制相关代码,例如:thread manager;
      包含代码:Activation_Queue.cpp      Process_Manager.cpp       Thread.cpp
  Atomic_Op.cpp             Process_Mutex.cpp         Thread_Adapter.cpp
  Atomic_Op_T.cpp           Process_Semaphore.cpp     Thread_Control.cpp
  File_Lock.cpp             RW_Process_Mutex.cpp      Thread_Exit.cpp
  Future.cpp                Synch.cpp                 Thread_Manager.cpp
  Future_Set.cpp            Synch_Options.cpp         Token.cpp
  Makefile                  Synch_T.cpp              
  Process.cpp               Test_and_Set.cpp         

ACE_Timer:该目录包含ACE中和时间相关的代码;
     包含代码:Timer_Heap.cpp
  Basic_Stats.cpp            Timer_Heap_T.cpp
  High_Res_Timer.cpp         Timer_List.cpp
  Makefile                   Timer_List_T.cpp
  Profile_Timer.cpp          Timer_Queue.cpp
  System_Time.cpp            Timer_Queue_Adapters.cpp
  Time_Request_Reply.cpp     Timer_Queue_T.cpp
  Timeprobe.cpp              Timer_Wheel.cpp
  Timeprobe_T.cpp            Timer_Wheel_T.cpp
  Timer_Hash.cpp            
  Timer_Hash_T.cpp          

ACE_Token:Token是ACE中实现的一种同步机制,保证严格的FIFO或LIFO策略来获得锁。ACE通过Token机制实现了分布式同步机制。
     包含代码:Local_Tokens.cpp          Token_Collection.cpp      Token_Request_Reply.cpp
  Makefile                  Token_Invariants.cpp     
  Remote_Tokens.cpp         Token_Manager.cpp        

ACE_Utils:ACE中的一些基础数据结构和算法的工具类代码;
    包含代码:ACE.cpp                             Init_ACE.cpp
  Active_Map_Manager.cpp              Intrusive_List.cpp
  Active_Map_Manager_T.cpp            Intrusive_List_Node.cpp
  Arg_Shifter.cpp                     Lib_Find.cpp
  Array_Base.cpp                      Makefile
  Auto_IncDec_T.cpp                   Managed_Object.cpp
  Auto_Ptr.cpp                        Map.cpp
  Cache_Map_Manager_T.cpp             Map_Manager.cpp
  Caching_Utility_T.cpp               Map_T.cpp
  Capabilities.cpp                    Message_Block.cpp
  Cleanup_Strategies_T.cpp            Message_Block_T.cpp
  Configuration.cpp                   Method_Request.cpp
  Configuration_Import_Export.cpp     Node.cpp
  Connection_Recycling_Strategy.cpp   Notification_Strategy.cpp
  Containers.cpp                      Object_Manager.cpp
  Containers_T.cpp                    Pair.cpp
  Date_Time.cpp                       Pair_T.cpp
  Dirent.cpp                          RB_Tree.cpp
  Dirent_Selector.cpp                 Recyclable.cpp
  Dynamic.cpp                         Refcountable.cpp
  Filecache.cpp                       Registry.cpp
  Flag_Manip.cpp                      SString.cpp
  Framework_Component.cpp             Sample_History.cpp
  Framework_Component_T.cpp           Singleton.cpp
  Free_List.cpp                       Stats.cpp
  Functor.cpp                         String_Base.cpp
  Functor_T.cpp                       String_Base_Const.cpp
  Get_Opt.cpp                         Swap.cpp
  Handle_Ops.cpp                      Unbounded_Queue.cpp
  Hash_Cache_Map_Manager_T.cpp        Unbounded_Set.cpp
  Hash_Map_Manager.cpp                Unbounded_Set_Ex.cpp
  Hash_Map_Manager_T.cpp              Vector_T.cpp
  Hash_Map_With_Allocator_T.cpp      
  Hashable.cpp                       

include:该目录又包含子目录ace,也就是说include/ace/目录下,包含了ACE的所有头文件和.i文件,之所以这样组织,是因为ACE中的源 文件和头文件的包含文件的方式为:#include "ace/OS.h",所以采用这种目录结构方式来存放头文件和.i文件。这里,对头文件和.i  文件,没有进一步按照功能划分,就是因为#include "ace/OS.h"这种包含方式,如果头文件和.i文件也按照功能划分,那么代码修改 量相当大;
            

通过上面给出的目录结构和源文件功能划分及头文件组织方式,相信读者以可以自行对ACE代码进行整理了。在实际整理和编译代码的过程中,需要修改Makefile和ACE头文件中以_T方式为后缀的头文件,例如:Obstack_T.h,需要修改里面模板源文件包含路径。我将在下一篇文章中进行描述。

我再次强调,上面ACE源码划分方式,不一定十分正确^_^,随着我们ACE学习和理解的深入,我们可能会进行更改。其实,在我们整理ACE源文件的时候,我们可以进一步了解ACE的各个源文件大致功能,对我们以后更深入的学习大有裨益。

posted @ 2006-02-26 22:04 heart in the world 阅读(538) | 评论 (0)编辑 收藏


2005年12月27日

致力于C/C++开发,致力于标准库,跨平台应用,致力于STL,ACE解决问题,致力于P2P网络领域研究!

posted @ 2005-12-27 23:06 heart in the world 阅读(354) | 评论 (0)编辑 收藏


仅列出标题  

posts - 4, comments - 8, trackbacks - 0, articles - 2

Copyright © heart in the world