user-0 提问:  MTTTY (Multi-Threaded TTY)里多文件的全局变量是怎么实现的？

回复:
user: user-0
content: 引用 11 楼 zhao4zhong1 的回复:编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E 我按你说看的，看了生成的宏展开后对应的.i文件，的确每个都包含了MTTTY.h的内容 比如MTTTY.h 里定义的一个 HWND          ghwndMain;所有生成的.i都有这一句

user: user-1
content: 编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E

user: user-0
content: 引用 3 楼 lovesmiles 的回复:看一下有没有static限定词，如果有，则是将变量的链接属性限定在文件内部。  静态自由函数、静态友元函数、静态变量的定义,const常量定义这些都是内部链接。 我搜索了整个头文件没有使用static，至于静态友元函数，这个项目是C写的，应该不会有这些的 前面有整个头文件的源码

user: user-0
content: 引用 7 楼 Cnwanglin 的回复:[quote=引用 5 楼 clearaelc 的回复:] [quote=引用 1 楼 zjq9931 的回复:] 头文件里面都有防止重复包含的宏定义。 一般是这样： #ifndef XXXX_XXXX #define XXXX_XXXX //全局变量。。。。。 #endif 这个头文件没有防止重复包含的宏定义 而且要是有了，其他文件用了这个头文件的变量应该都不识别了吧？[/quote]   #ifndef  #define   #endif  如果没有,就会出现变量重复定义,必须要有[/quote] 的确是没有，而且也没有报错，我就奇怪是怎么做到的 前面的回复，有张VS生成的文件包含图 这是myttty.h文件  /*-----------------------------------------------------------------------------     This is a part of the Microsoft Source Code Samples.      Copyright (C) 1995 Microsoft Corporation.     All rights reserved.      This source code is only intended as a supplement to      Microsoft Development Tools and/or WinHelp documentation.     See these sources for detailed information regarding the      Microsoft samples programs.      MODULE: MTTTY.h      PURPOSE: Contains global definitions and variables  -----------------------------------------------------------------------------*/  // // File: MTTTY.h //  #include "resource.h" #include "ttyinfo.h"  // // GLOBAL DEFINES // #define TTY_BUFFER_SIZE         MAXROWS * MAXCOLS #define MAX_STATUS_BUFFER       20000 #define MAX_WRITE_BUFFER        1024 #define MAX_READ_BUFFER         2048 #define READ_TIMEOUT            500 #define STATUS_CHECK_TIMEOUT    500 #define WRITE_CHECK_TIMEOUT     500 #define PURGE_FLAGS             PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR  #define EVENTFLAGS_DEFAULT      EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD #define FLAGCHAR_DEFAULT        '\n'  // // Write request types // #define WRITE_CHAR          0x01 #define WRITE_FILE          0x02 #define WRITE_FILESTART     0x03 #define WRITE_FILEEND       0x04 #define WRITE_ABORT         0x05 #define WRITE_BLOCK         0x06  // // Read states // #define RECEIVE_TTY         0x01 #define RECEIVE_CAPTURED    0x02  // // window coords // #define MAXXWINDOW          750 #define MAXYWINDOW          530 #define STARTXWINDOW        80 #define STARTYWINDOW        70  #define SETTINGSFACTOR      5 #define STATUSFACTOR        5  // // window timer ids //  #define TIMERID             1  // // GLOBAL VARIABLES // OSVERSIONINFO gOSV; HINSTANCE     ghInst; HACCEL        ghAccel; HWND          ghwndMain; HWND          ghWndToolbarDlg; HWND          ghWndStatusDlg; HWND          ghWndTTY; HWND          ghWndHidden;  // // COMMTIMEOUTS is init'd in Init.c // extern COMMTIMEOUTS gTimeoutsDefault;  // //  Window placement variables // WORD gwBaseY; LONG gcyMinimumWindowHeight;  // //  Flags controlling thread actions // HANDLE ghThreadExitEvent; BOOL gfAbortTransfer;  // //  File transfer variables // DWORD  gdwFileTransferLeft; DWORD  gdwReceiveState; HANDLE ghFileCapture;  // //  Status updating // CRITICAL_SECTION gStatusCritical; HANDLE ghStatusMessageEvent; HANDLE ghStatusMessageHeap; HFONT ghFontStatus; int   gnStatusIndex;  typedef struct STATUS_MESSAGE;  struct STATUS_MESSAGE * glpStatusMessageHead; struct STATUS_MESSAGE * glpStatusMessageTail;  typedef struct STATUS_MESSAGE {     struct STATUS_MESSAGE * lpNext;     // pointer to next node     char chMessageStart;                // variable length string start here } STATUS_MESSAGE;   // //  Port name // char gszPort[10];  // //  Writer heap variables // CRITICAL_SECTION gcsWriterHeap; CRITICAL_SECTION gcsDataHeap; HANDLE ghWriterHeap; HANDLE ghWriterEvent; HANDLE ghTransferCompleteEvent;  // //  Write request data structure; look in Writer.c for more info // typedef struct WRITEREQUEST;  struct WRITEREQUEST *gpWriterHead; struct WRITEREQUEST *gpWriterTail;  typedef struct WRITEREQUEST {   DWORD      dwWriteType;        // char, file start, file abort, file packet   DWORD      dwSize;             // size of buffer   char       ch;                 // ch to send   char *     lpBuf;              // address of buffer to send   HANDLE     hHeap;              // heap containing buffer   HWND       hWndProgress;       // status bar window handle   struct WRITEREQUEST *pNext;    // next node in the list   struct WRITEREQUEST *pPrev;    // prev node in the list } WRITEREQUEST, *PWRITEREQUEST;   // // Prototypes of functions called between source files //  // //  Error functions // void ErrorReporter( char * szMessage ); void ErrorHandler( char * szMessage ); void ErrorInComm( char * szMessage );  // //  Initialization/deinitialization/settings functions // HANDLE SetupCommPort( void ); void ChangeConnection( HWND, BOOL ); BOOL BreakDownCommPort( void ); BOOL UpdateConnection( void ); void GlobalInitialize( void ); void DestroyTTYInfo( void ); void GlobalCleanup( void ); void UpdateTTYInfo( void ); BOOL DisconnectOK( void ); BOOL InitTTYInfo( void ); void InitNewFont( LOGFONT, COLORREF );  // //  TTY functions // void OpenSettingsToolbar( HWND ); void OpenStatusToolbar( HWND ); BOOL CmdAbout( HWND );  // //  TTY functions // BOOL MoveTTYCursor( HWND ); BOOL KillTTYFocus( HWND ); BOOL SetTTYFocus( HWND ); BOOL SizeTTY( HWND, WORD, WORD );  // //  Thread procedures // DWORD WINAPI ReaderAndStatusProc( LPVOID ); DWORD WINAPI WriterProc( LPVOID );  // //  File transfer functions // void CALLBACK TransferRepeatDo( UINT, UINT, DWORD, DWORD, DWORD );   void TransferRepeatCreate( LPCSTR, DWORD ); void TransferRepeatDestroy( void ); void TransferFileTextStart( LPCSTR ); void TransferFileTextEnd( void ); // void TransferFileText( LPCTSTR ); void ReceiveFileText( LPCTSTR ); DWORD GetAFrequency( void );  // //  Buffer manipulation functions // void OutputABufferToWindow( HWND, char *, DWORD ); void OutputABuffer( HWND, char *, DWORD ); BOOL ClearTTYContents( void );  // //  Status functions // HFONT CreateStatusEditFont( void ); void ReportStatusEvent( DWORD );  void CheckModemStatus( BOOL ); void ReportCommError( void ); void ReportComStat( COMSTAT ); void StatusMessage( void ); void UpdateStatus( char * ); void CheckComStat( BOOL );  // //  Writer heap functions // BOOL WriterAddNewNode( DWORD, DWORD, char, char *, HANDLE, HWND ); BOOL WriterAddExistingNode( PWRITEREQUEST, DWORD, DWORD, char, char *, HANDLE, HWND ); BOOL WriterAddNewNodeTimeout( DWORD, DWORD, char, char *, HANDLE, HWND, DWORD ); BOOL WriterAddFirstNodeTimeout( DWORD, DWORD, char, char *, HANDLE, HWND, DWORD );

user: user-0
content: 引用 2 楼 xxxxing 的回复:不引用 公共头文件，需要什么变量在自己的头文件里面定义。 ----------------------- 我用vs2013生成生成了包含文件关系图是这样的  每个.c都是包含中这个"mttty.h"的

user: user-2
content: 引用 5 楼 clearaelc 的回复:[quote=引用 1 楼 zjq9931 的回复:] 头文件里面都有防止重复包含的宏定义。 一般是这样： #ifndef XXXX_XXXX #define XXXX_XXXX //全局变量。。。。。 #endif 这个头文件没有防止重复包含的宏定义 而且要是有了，其他文件用了这个头文件的变量应该都不识别了吧？[/quote]   #ifndef  #define   #endif  如果没有,就会出现变量重复定义,必须要有

user: user-3
content: 引用 5 楼 clearaelc 的回复:[quote=引用 1 楼 zjq9931 的回复:] 头文件里面都有防止重复包含的宏定义。 一般是这样： #ifndef XXXX_XXXX #define XXXX_XXXX //全局变量。。。。。 #endif 这个头文件没有防止重复包含的宏定义 而且要是有了，其他文件用了这个头文件的变量应该都不识别了吧？[/quote] 识别的了。 防止重复包含的宏定义目的是防止重复包含，没有重复包含的都可以用。已经包含了的就不会重复。

user: user-0
content: 引用 1 楼 zjq9931 的回复:头文件里面都有防止重复包含的宏定义。 一般是这样： #ifndef XXXX_XXXX #define XXXX_XXXX //全局变量。。。。。 #endif 这个头文件没有防止重复包含的宏定义 而且要是有了，其他文件用了这个头文件的变量应该都不识别了吧？

user: user-0
content: "mttty.h"的内容是这样的 #include "resource.h" #include "ttyinfo.h" 一堆#define OSVERSIONINFO gOSV; HINSTANCE     ghInst; HACCEL        ghAccel; HWND          ghwndMain; HWND          ghWndToolbarDlg; HWND          ghWndStatusDlg; HWND          ghWndTTY; HWND          ghWndHidden; extern COMMTIMEOUTS gTimeoutsDefault; …… 函数声明 这是完整的项目 http://download.csdn.net/detail/clearaelc/7738951

user: user-4
content: 看一下有没有static限定词，如果有，则是将变量的链接属性限定在文件内部。  静态自由函数、静态友元函数、静态变量的定义,const常量定义这些都是内部链接。

user: user-5
content: 不引用 公共头文件，需要什么变量在自己的头文件里面定义。 -----------------------

user: user-3
content: 头文件里面都有防止重复包含的宏定义。 一般是这样： #ifndef XXXX_XXXX #define XXXX_XXXX //全局变量。。。。。 #endif

user: user-0
content: 谢谢各位的回答！

user: user-4
content: 引用 17 楼 clearaelc 的回复:[quote=引用 13 楼 zhao4zhong1 的回复:] [quote=引用 12 楼 clearaelc 的回复:] [quote=引用 11 楼 zhao4zhong1 的回复:] 编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E 我按你说看的，看了生成的宏展开后对应的.i文件，的确每个都包含了MTTTY.h的内容 比如MTTTY.h 里定义的一个 HWND          ghwndMain;所有生成的.i都有这一句 [/quote] 严重怀疑link时会将同名声明合并为一个。 试试在怀疑不同.c中引用全局变量XXXXX不是同一个内存变量的地方用printf("addr of global var XXXXX is %p\n",&XXXXX);[/quote] 这个方法我发之前就试过了，是一样的 刚刚我建了一个项目用.c作后缀的，居然通过编译了，看来是C会对同名全局变量会合并的 另外“link时会将同名声明合并为一个”，头文件的难道不是定义吗？怎么会是声明？[/quote]  是的，这个问题我也发现了。 相同的代码，将c文件改成cpp链接时就会出错。  显然c和c++的链接是不太一样的。等级懂的人回答你吧。

user: user-0
content: 引用 13 楼 zhao4zhong1 的回复:[quote=引用 12 楼 clearaelc 的回复:] [quote=引用 11 楼 zhao4zhong1 的回复:] 编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E 我按你说看的，看了生成的宏展开后对应的.i文件，的确每个都包含了MTTTY.h的内容 比如MTTTY.h 里定义的一个 HWND          ghwndMain;所有生成的.i都有这一句 [/quote] 严重怀疑link时会将同名声明合并为一个。 试试在怀疑不同.c中引用全局变量XXXXX不是同一个内存变量的地方用printf("addr of global var XXXXX is %p\n",&XXXXX);[/quote] 这个方法我发之前就试过了，是一样的 刚刚我建了一个项目用.c作后缀的，居然通过编译了，看来是C会对同名全局变量会合并的 另外“link时会将同名声明合并为一个”，头文件的难道不是定义吗？怎么会是声明？

user: user-2
content: 引用 15 楼 user-6 的回复:纯c的吧，没初始化的叫做tentative definition可重复。c++不允许，链接时会报错说多处重复定义...  正解,  鼓掌!

user: user-6
content: 纯c的吧，没初始化的叫做tentative definition可重复。c++不允许，链接时会报错说多处重复定义...

user: user-1
content: printf("addr of global var XXXXX in %s is %p\n",__FILE__,&XXXXX);

user: user-1
content: 引用 12 楼 clearaelc 的回复:[quote=引用 11 楼 zhao4zhong1 的回复:] 编译选项加/EP /P，重新编译，查看宏展开后对应的.i文件。gcc加-E 我按你说看的，看了生成的宏展开后对应的.i文件，的确每个都包含了MTTTY.h的内容 比如MTTTY.h 里定义的一个 HWND          ghwndMain;所有生成的.i都有这一句 [/quote] 严重怀疑link时会将同名声明合并为一个。 试试在怀疑不同.c中引用全局变量XXXXX不是同一个内存变量的地方用printf("addr of global var XXXXX is %p\n",&XXXXX);