一、typedef基本介绍

typedef作用是为变量引入一种新的名字,typedef的格式与变量申明完全一致,只是在前面加了一个typedef关键字。typedef并没有创建一个新的变量,只是表明这个名字是指定类型的同义词。简单的例子如下:

typedef int Length;
Length len,maxlen;

但是,一般情况,采用typedef就是为了让复杂的申明方式变得简单,比如结构体(Struct)、指针申明的变量:

typedef char *String;

typedef中声明的类型在变量名的位置出现,而不是紧接在关键字typedef之后,上面的代码表示的类型是char *,类型名是String。

char *lineptr[MAXLINES];
char *alloc(int n);
/* 上面的代码等价于 */
String lineptr[MAXLINES],alloc(int);

上面的代码固然是有点用,但还算简单。

typedef类似于#define语句,但由于typedef是由编译器解释的(#define通过预处理器实现替换),因此它的文本替换功能要超过预处理器(#define)的能力。比如typedef可以作用于指向函数的指针,如下:

typedef int (*FP)();//pointer to function returning int
typedef int F(int);//function with one int parameter,returning int

该怎么使用呢?

FP fp;//pointer to a function returning int
F *fp2;//pointer to a function taking an int parameter and returning an int

采用typedef重命名指向函数的指针,能有多大用呢?有些地方还真是很有用。

二、typedef的高级应用

来看一个高级一点的例子,那就是DLL(动态链接库)共享内存问题。多个进程可以共享动态链接库中相同的代码,但是由DLL维护的数据对每个进程是不一样的,所以每个进程都有自己的、供DLL使用数据的地址空间,要实现进程间共享数据还需要一些额外的工作。

这里还是拿《windows程序设计》中的代码例子来说明。先看关于一个关于DLL链接库模块的代码:

/*----------------------
   STRLIB.H header file
  ----------------------*/

#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif

     // The maximum number of strings STRLIB will store and their lengths

#define MAX_STRINGS 256
#define MAX_LENGTH  64

     // The callback function type definition uses generic strings

typedef BOOL (CALLBACK * GETSTRCB) (PCTSTR, PVOID) ;

     // Each function has ANSI and Unicode versions

EXPORT BOOL CALLBACK AddStringA (PCSTR) ;
EXPORT BOOL CALLBACK AddStringW (PCWSTR) ;

EXPORT BOOL CALLBACK DeleteStringA (PCSTR) ;
EXPORT BOOL CALLBACK DeleteStringW (PCWSTR) ;

EXPORT int CALLBACK GetStringsA (GETSTRCB, PVOID) ;
EXPORT int CALLBACK GetStringsW (GETSTRCB, PVOID) ;

     // Use the correct version depending on the UNICODE identifier

#ifdef UNICODE
#define AddString    AddStringW
#define DeleteString DeleteStringW
#define GetStrings   GetStringsW
#else
#define AddString    AddStringA
#define DeleteString DeleteStringA
#define GetStrings   GetStringsA
#endif
/*------------------------------------------------
   STRLIB.C -- Library module for STRPROG program
               (c) Charles Petzold, 1998
  ------------------------------------------------*/

#include <windows.h>
#include <wchar.h>       // for wide-character string functions
#include "strlib.h"

     // shared memory section (requires /SECTION:shared,RWS in link options)

#pragma data_seg ("shared")
int   iTotal = 0 ;
WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ;
#pragma data_seg ()

#pragma comment(linker,"/SECTION:shared,RWS")

int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
     return TRUE ;
}

EXPORT BOOL CALLBACK AddStringA (PCSTR pStringIn)
{
     BOOL  bReturn ;
     int   iLength ;
     PWSTR pWideStr ;

          // Convert string to Unicode and call AddStringW

     iLength = MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, NULL, 0) ;
     pWideStr = malloc (iLength) ;
     MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, pWideStr, iLength) ;
     bReturn = AddStringW (pWideStr) ;
     free (pWideStr) ;

     return bReturn ;
}

EXPORT BOOL CALLBACK AddStringW (PCWSTR pStringIn)
{
     PWSTR pString ;
     int   i, iLength ;
     
     if (iTotal == MAX_STRINGS - 1)
          return FALSE ;
     
     if ((iLength = wcslen (pStringIn)) == 0)
          return FALSE ;

          // Allocate memory for storing string, copy it, convert to upper case

     pString = malloc (sizeof (WCHAR) * (1 + iLength)) ;
     wcscpy (pString, pStringIn) ;
     _wcsupr (pString) ;

          // Alphabetize the strings
     
     for (i = iTotal ; i > 0 ; i--)
     {
          if (wcscmp (pString, szStrings[i - 1]) >= 0)
               break ;
          
          wcscpy (szStrings[i], szStrings[i - 1]) ;
     }
     wcscpy (szStrings[i], pString) ;
     iTotal++ ;

     free (pString) ;
     return TRUE ;
}

EXPORT BOOL CALLBACK DeleteStringA (PCSTR pStringIn)
{
     BOOL  bReturn ;
     int   iLength ;
     PWSTR pWideStr ;

          // Convert string to Unicode and call DeleteStringW

     iLength = MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, NULL, 0) ;
     pWideStr = malloc (iLength) ;
     MultiByteToWideChar (CP_ACP, 0, pStringIn, -1, pWideStr, iLength) ;
     bReturn = DeleteStringW (pWideStr) ;
     free (pWideStr) ;

     return bReturn ;
}

EXPORT BOOL CALLBACK DeleteStringW (PCWSTR pStringIn)
{
     int i, j ;
     
     if (0 == wcslen (pStringIn))
          return FALSE ;
     
     for (i = 0 ; i < iTotal ; i++)
     {
          if (_wcsicmp (szStrings[i], pStringIn) == 0)
               break ;
     }
          // If given string not in list, return without taking action
     
     if (i == iTotal)
          return FALSE ;
     
          // Else adjust list downward
     
     for (j = i ; j < iTotal ; j++)
          wcscpy (szStrings[j], szStrings[j + 1]) ;
     
     szStrings[iTotal--][0] = '\0' ;
     return TRUE ;
}

EXPORT int CALLBACK GetStringsA (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
     BOOL bReturn ;
     int  i, iLength ;
     PSTR pAnsiStr ;

     for (i = 0 ; i < iTotal ; i++)
     {
               // Convert string from Unicode

          iLength = WideCharToMultiByte (CP_ACP, 0, szStrings[i], -1, NULL, 0,
                                         NULL, NULL) ;
          pAnsiStr = malloc (iLength) ;
          WideCharToMultiByte (CP_ACP, 0, szStrings[i], -1, pAnsiStr, iLength,
                                          NULL, NULL) ;

               // Call callback function

          bReturn = pfnGetStrCallBack (pAnsiStr, pParam) ;
          
          if (bReturn == FALSE)
               return i + 1 ;

          free (pAnsiStr) ;
     }
     return iTotal ;
}

EXPORT int CALLBACK GetStringsW (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
     BOOL bReturn ;
     int  i ;
     
     for (i = 0 ; i < iTotal ; i++)
     {
          bReturn = pfnGetStrCallBack ((PCTSTR)szStrings[i], pParam) ;
          
          if (bReturn == FALSE)
               return i + 1 ;
     }
     return iTotal ;
}

上面的代码,就是创建一个dll文件,实现对UNICODE与非UNICODE版本的字串符增加、删除、获取的函数。但是还是有几点需要强调一下。

1,使C和C++都能使用该DLL。需要在strlib.h文件头部加上以下代码:

#ifdef __cplusplus
#define EXPORT extern "C" __declspec (dllexport)
#else
#define EXPORT __declspec (dllexport)
#endif

2,实现DLL共享内存需要在strlib.c文件中做特别申明:

// shared memory section (requires /SECTION:shared,RWS in link options)

#pragma data_seg ("shared")
int   iTotal = 0 ;
WCHAR szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ;
#pragma data_seg ()

#pragma comment(linker,"/SECTION:shared,RWS")

上面的"shared"表示该数据区的名字,当然也可以定义成其它的名字。iTotal、szStrings表示需要共享的变量。最后一句,表示将shared数据区,通知给链接器,RWS表明该数据区具有可读、可写和可共享的属性。

3,typedef与回调函数的密切配合,在strlib.h文件中有句代码:

typedef BOOL (CALLBACK * GETSTRCB) (PCTSTR, PVOID) ;

这个代码的用处在strlib.c文件中体现出了价值:

EXPORT int CALLBACK GetStringsA (GETSTRCB pfnGetStrCallBack, PVOID pParam){
....
bReturn = pfnGetStrCallBack (pAnsiStr, pParam) ;
....
}

EXPORT int CALLBACK GetStringsW (GETSTRCB pfnGetStrCallBack, PVOID pParam)
{
....
bReturn = pfnGetStrCallBack (szStrings[i], pParam) ;
....
}

可以看出,上面的pfnGetStrCallBack参数就是一个函数,但是函数的声明来自于strlib.h,但是具体的实现却在外部的调用程序中。这种通过typedef在头文件声明的方式让程序的结构性和可读性都有较大提升。

下面是调用这个dll的程序代码(rc和头文件省略):

/*--------------------------------------------------------
   STRPROG.C -- Program using STRLIB dynamic-link library
                (c) Charles Petzold, 1998
  --------------------------------------------------------*/

#include <windows.h>
#include "strlib.h"
#include "resource.h"

typedef struct
{
     HDC hdc ;
     int xText ;
     int yText ;
     int xStart ;
     int yStart ;
     int xIncr ;
     int yIncr ;
     int xMax ;
     int yMax ;
}
CBPARAM ;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

TCHAR szAppName [] = TEXT ("StrProg") ;
TCHAR szString [MAX_LENGTH + 1] ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     HWND     hwnd ;
     MSG      msg ;
     WNDCLASS wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = szAppName ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("DLL Demonstration Program"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
     switch (message)
     {
     case WM_INITDIALOG:
          SendDlgItemMessage (hDlg, IDC_STRING, EM_LIMITTEXT, MAX_LENGTH, 0) ;
          return TRUE ;
          
     case WM_COMMAND:
          switch (wParam)
          {
          case IDOK:
               GetDlgItemText (hDlg, IDC_STRING, szString, MAX_LENGTH) ;
               EndDialog (hDlg, TRUE) ;
               return TRUE ;
               
          case IDCANCEL:
               EndDialog (hDlg, FALSE) ;
               return TRUE ;
          }
     }
     return FALSE ;
}

BOOL CALLBACK GetStrCallBack (PTSTR pString, CBPARAM * pcbp)
{
     TextOut (pcbp->hdc, pcbp->xText, pcbp->yText,
              pString, lstrlen (pString)) ;
     
     if ((pcbp->yText += pcbp->yIncr) > pcbp->yMax)
     {
          pcbp->yText = pcbp->yStart ;
          if ((pcbp->xText += pcbp->xIncr) > pcbp->xMax)
               return FALSE ;
     }
     return TRUE ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HINSTANCE  hInst ;
     static int        cxChar, cyChar, cxClient, cyClient ;
     static UINT       iDataChangeMsg ;
     CBPARAM           cbparam ;
     HDC               hdc ;
     PAINTSTRUCT       ps ;
     TEXTMETRIC        tm ;
     
     switch (message)
     {
     case WM_CREATE:
          hInst = ((LPCREATESTRUCT) lParam)->hInstance ;
          hdc   = GetDC (hwnd) ;
          GetTextMetrics (hdc, &tm) ;
          cxChar = (int) tm.tmAveCharWidth ;
          cyChar = (int) (tm.tmHeight + tm.tmExternalLeading) ;
          ReleaseDC (hwnd, hdc) ;

               // Register message for notifying instances of data changes

          iDataChangeMsg = RegisterWindowMessage (TEXT ("StrProgDataChange")) ;
          return 0 ;
          
     case WM_COMMAND:
          switch (wParam)
          {
          case IDM_ENTER:
               if (DialogBox (hInst, TEXT ("EnterDlg"), hwnd, &DlgProc))
               {
                    if (AddString (szString))
                         PostMessage (HWND_BROADCAST, iDataChangeMsg, 0, 0) ;
                    else
                         MessageBeep (0) ;
               }
               break ;
               
          case IDM_DELETE:
               if (DialogBox (hInst, TEXT ("DeleteDlg"), hwnd, &DlgProc))
               {
                    if (DeleteString (szString))
                         PostMessage (HWND_BROADCAST, iDataChangeMsg, 0, 0) ;
                    else
                         MessageBeep (0) ;
               }
               break ;
          }
          return 0 ;
          
     case WM_SIZE:
          cxClient = (int) LOWORD (lParam) ;
          cyClient = (int) HIWORD (lParam) ;
          return 0 ;
               
     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
               
          cbparam.hdc   = hdc ;
          cbparam.xText = cbparam.xStart = cxChar ;
          cbparam.yText = cbparam.yStart = cyChar ;
          cbparam.xIncr = cxChar * MAX_LENGTH ;
          cbparam.yIncr = cyChar ;
          cbparam.xMax  = cbparam.xIncr * (1 + cxClient / cbparam.xIncr) ;
          cbparam.yMax  = cyChar * (cyClient / cyChar - 1) ;
               
          GetStrings ((GETSTRCB) GetStrCallBack, (PVOID) &cbparam) ;
              
          EndPaint (hwnd, &ps) ;
          return 0 ;
               
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;

     default:
          if (message == iDataChangeMsg)
               InvalidateRect (hwnd, NULL, TRUE) ;
          break ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

这个程序的起始处便通过#include "strlib.h"引用dll的头文件,得到GETSTRCB函数指针的定义格式,然后编写具体实现该函数的细节(即dll文件中,只是定义了一个函数的名字,具体实现在外部调用的程序中实现):

BOOL CALLBACK GetStrCallBack (PTSTR pString, CBPARAM * pcbp)
{
     TextOut (pcbp->hdc, pcbp->xText, pcbp->yText,
              pString, lstrlen (pString)) ;
     
     if ((pcbp->yText += pcbp->yIncr) > pcbp->yMax)
     {
          pcbp->yText = pcbp->yStart ;
          if ((pcbp->xText += pcbp->xIncr) > pcbp->xMax)
               return FALSE ;
     }
     return TRUE ;
}

....
//调用时再转型
GetStrings ((GETSTRCB) GetStrCallBack, (PVOID) &cbparam) ;

注:1,这个程序有点复杂,但正如所看到的那样,只有在复杂的程序中,才更能体现出typedef的价值;

       2,这个程序在VC++中可以实现内存共享,但是如果用dev c++,则共享没有效果。

该程序实现效果如下:

typescript 字符串替换 所有 typedef字符串_c/c++

也就是同时打开多个对话框时,在任意一个对话框中输入一些数据,那么另一个对话框内的数据也会跟着发生变化。