UNICODE与ANSI的区别 (转)

        什么是ANSI,什么又是UNICODE呢?其实这是两种不同的编码方式标准,ANSI中的字符采用8bit,而UNICODE中的字符采用16bit。(对于字符来说ANSI以单字节存放英文字符,以双字节存放中文等字符,而Unicode下,英文和中文的字符都以双字节存放)Unicode码也是一种国际标准编码,采用二个字节编码,与ANSI码不兼容。目前,在网络、Windows系统和很多大型软件中得到应用。8bit的ANSI编码只能表示256种字符,表示26个英文字母是绰绰有余的,但是表示汉字,韩国语等有着成千上万个字符的非西方字符肯定就不够了,正是如此才引入了UNICODE标准。   
     在软件开发中,特别是使用C语言的一些有关字符串处理的函数,ANSI和UNICODE是区分是用的,那么ANSI类型的字符和UNICODE类型的字符如何定义,如何使用呢?ANSI和UNICODE又如何转换呢?   
   一.定义部分:  
   ANSI:char    str[1024]; 可用字符串处理函数:strcpy( ),    strcat( ),   strlen( )等等。
UNICODE:wchar_t    str[1024];可用字符串处理函数   
二.可用函数: 
   ANSI:即char,可用字符串处理函数:strcat(    ),strcpy(    ),    strlen(    )等以str打头的函数。   
   UNICODE:即wchar_t 可用字符串处理函数:wcscat(),wcscpy(),wcslen()等以wcs打头的函数。   
   三.系统支持  
      Windows    98    :只支持ANSI。   
      Windows    2k    :既支持ANSI又支持UNICODE。   
      Windows    CE    :只支持UNICODE。   
      说明   
      1 在COM里面只支持UNICODE。   
      2.Windows   2000整个OS系统都是基于UNICODE的,为此在windows 2000 下使用ANSI是需要付出代价的,虽然在编码上不用任何的转换,但是这种转化是隐藏的,是占用系统资源的(CPU,内存)。   
      3 在Windows 98下必须使用UNICODE,则需要自己手动的编码切换。   
    四.如何区分:   
    在我们软件开发中往往需要即支持ANSI又支持UNICODE,不可能在要求类型转换的时候,重新改变字符串的类型,和使用于字符串上的操作函数。为此, 标准C运行期库和Windows 提供了宏定义的方式。   
    在C语言里面提供了 _UNICODE宏(有下划线),在Windows里面提供了UNICODE宏(无下划线),只要定了_UNICODE宏和UNICODE宏,系统就会自动切换到UNICODE版本,否则,系统按照ANSI的方式进行编译和运行。   
    只定义了宏并不能实现自动的转换,他还需要一系列的字符定义支持。   
   1. TCHAR   
   如果定义了UNICODE宏则TCHAR被定义为wchar_t。   
    typedef    wchar_t    TCHAR;   
    否则TCHAR被定义为char   
    typedef    char   TCHAR;   
   2.LPTSTR   
如果定义了UNICODE宏则LPTSTR被定义为LPWSTR。(以前一直不知道LPWSTR是什么东东,终于明白了)   
   typedef    LPTSTR   LPWSTR;   
   否则TCHAR被定义为char   
   typedef    LPTSTR   LPSTR;  
补充一下:
UTF-8是可以用于真正的流式传输的,Unicode是一种编码方案   
    我的理解是UTF-8是Unicode的一种具体实现。类似的实现还有UTF-16等等。


ANSI/Unicode字符和字符串 
TChar.h是String.h的修改,用于创建ANSI/Unicode通用字符串。

Unicode字符串的每个字符都是16位的。

Win9x只支持ANSI;Win2000/XP/2003支持ANSI/Unicode;WinCE只支持Unicode
       附:有部分Unicode函数也可以在Win9X中使用,但可能会出现意想不到错误。

wchar_t是Unicode字符的数据类型。

所有的Unicode函数均以wcs开头,ANSI函数均以str开头;ANSI C规定C运行期库支持ANSI和Unicode
                                 ANSI                                                                              Unicode
       char   *strcat(char   *,   const   char   *)                           wchar_t   *wcscat(wchar_t   *,   const   wchar_t   *) 
       char   *strchr(const   char * , int)                                   wchar_t    *wcschr(const   wchar_t   * , int) 
       int   strcmp(const   char   *,    const   char   *)                int    wcscmp(const   wchar_t   *, const   wchar_t *)
       char *strcpy(char   *,   const   char   *)                           wchar_t   *wcscpy(wchar_t    *,   const   wchar_t    *)
       size_t   strlen(const   char   *)                                        wchar_t    wcslen(const   wchar_t   *)

L" wash " : 用于将ANSI字符串转换为Unicode字符串;
        _TEXT(" wash ")根据是否定义Unicode或_Unicode进行转换。
       附:_Unicode用于C运行库;Unicode用于Windows头文件。

ANSI/Unicode通用数据类型
                        Both(ANSI/Unicode)                    ANSI                       Unicode
                               LPCTSTR                                 LPCSTR                   LPCWSTR
                               LPTSTR                                    LPSTR                      LPWSTR
                               PCTSTR                                   PCSTR                      PCWSTR
                               PTSTR                                      PSTR                         PWSTR
                               TBYTE(TCHAR)                      CHAR                         WCHAR

在设计dll时最好提供ANSI和Unicode函数,ANSI函数只用于分配内存,将字符转换为Unicode字符,然后调用Unicode函数。

最好使用操作系统函数,少使用或不实用C运行期函数
        eg:操作系统字符串函数(shlWApi.h)
                StrCat(), StrChr(), StrCmp(), StrCpy()等
                注意它们区分大小写,也区分ANSI和Unicode版本
        附:ANSI版函数在原函数后加大写字母A
                Unicode函数在原函数后加大写字母W

成为符合ANSI和Unicode的函数
        ? 将文本串视为字符数组,而不是c h a r s数组或字节数组。
        ? 将通用数据类型(如T C H A R和P T S T R)用于文本字符和字符串。
        ? 将显式数据类型(如B Y T E和P B Y T E)用于字节、字节指针和数据缓存。
        ? 将T E X T宏用于原义字符和字符串。
        ? 修改字符串运算问题 。
          如:sizeof(szBuffer) -> sizeof(szBuffer) / sizeof(TCHAR)
                  malloc(charNum) -> malloc(charNum * sizeof(TCHAR))   

对Unicode字符操作的函数还有:(也有ANSI和Unicode版本)
       lstrcat() , lstrcmp() / lstrcmpi()[ 它们在内部调用CompareString() ], lstrcpy(), lstrlen()
       这些是作为宏实现的。

          C运行期函数                                       windows函数
                  tolower()                                  PTSTR   CharLower(PTSTR   pszString)
                  toupper()                                 PTSTR   CharUpper(PTSTR   pszString)
                  isalpha()                                  BOOL   IsCharAlpha(TCHAR   ch)
                                                                   BOOL   ISCharAlphaNumeric(TCHAR   ch)
                  islower()                                  BOOL   IsCharLower(TCHAR   ch)
                  isupper()                                 BOOL   IsCharUpper(TCHAR   ch)
                  print()                                       wsprintf()
       转换Buffer:DWORD   CharLowerBuffer(PTSTR   pszString , DWORD cchString)
                              DWORD CharUpperBuffer(PTSTR   pszString , DWORD   cchString)
       也可转换单个字符,如:TCHAR   cLowerCaseChar = CharLower((PTSTR)szString[0])

确定字符是ANSI或Unicode
        BOOL   IsTextUnicode(
                     const   VOID   * pBuffer,   //input   buffer   to be   examined
                     int   cb,                               //size of input   buffer
                     LPINT   lpi                         //options
        )
       附:此函数在Win9x系统中,没有实现代码,始终返回FALSE

Unicode与ANSI之间的转换
        char   szA[40];
        wchar   szW[40];
        // Normal   sprintf : all   string   are   ANSI
        sprintf( szA , " %s " , " ANSI   str ");
        // Convert   Unicode   string   to ANSI
        sprintf(   szA,   " %S " ,   L" Unicode   str ");
        // Normal   swprintf : all string are unicode
        swprinf( szW , "%s" , L" Unicode   str ");
        // Convert   ANSI   String to Unicode
        swprinf( szW, L"%S" , "ANSI str");

        int   MultiByteToWideChar(
              UINT   uCodePage,                   //code page,   0
              DWORD   dwFlags,                   //character-type   options,   0
              PCSTR   pMultiByte,                  //source   string   Addr
              int   cchMultiByte,                       //source   string   byte length
              PWSTR   pWideCharStr,          //Dest string   Addr
              int   cchWideChar                      //Dest   string char   Nums
         )
        u C o d e P a g e参数用于标识一个与多字节字符串相关的代码页号。d w F l a g s参数用于设定另一个控件,它可以用重音符号之类的区分标记来影响字符。这些标志通常并不使用,在d w F l a g s参数中传递0。p M u l t i B y t e S t r参数用于设定要转换的字符串, c c h M u l t i B y t e参数用于指明该字符串的长度(按字节计算)。如果为c c h M u l t i B y t e参数传递- 1,那么该函数用于确定源字符串的长度。转换后产生的U n i c o d e版本字符串将被写入内存中的缓存,其地址由p Wi d e C h a r S t r参数指定。必须在c c h Wi d e C h a r参数中设定该缓存的最大值(以字符为计量单位)。如果调用M u l t i B y t e To Wi d e C h a r,给c c h Wi d e C h a r参数传递0,那么该参数将不执行字符串的转换,而是返回为使转换取得成功所需要的缓存的值。

     可以通过下列步骤将多字节字符串转换成U n i c o d e等价字符串:
     1) 调用M u l t i B y t e To Wi d e C h a r函数,为p Wi d e C h a r S t r参数传递N U L L,为c c h Wi d e C h a r参数传递0。
     2) 分配足够的内存块,用于存放转换后的U n i c o d e字符串。该内存块的大小由前面对M u l t B y t e To Wi d e C h a r的调用返回。
     3) 再次调用M u l t i B y t e To Wi d e C h a r,这次将缓存的地址作为p Wi d e C h a r S t r参数来传递,并传递第一次调用M u l t i B y t e To Wi d e C h a r时返回的缓存大小,作为c c h Wi d e c h a r参数。
     4) 使用转换后的字符串。
     5) 释放U n i c o d e字符串占用的内存块。

    int WideCharToMultiByte(
          UINT CodePage,                        // code page
          DWORD dwFlags,                      // performance and mapping flags
          LPCWSTR lpWideCharStr,      // wide-character string
          int cchWideChar,                       // number of chars in string
          LPSTR lpMultiByteStr,               // buffer for new string
          int cbMultiByte,                           // size of buffer
          LPCSTR lpDefaultChar,            // default for unmappable chars
          LPBOOL lpUsedDefaultChar   // set when default char used
     )

 

本文转自:http://hi.baidu.com/%C6%DF%D4%C2%BA%A3%C0%B6/blog/item/65639b25cc31f16234a80fc4.html

posted @ 2011-09-07 16:21 Daywei 阅读(825) | 评论 (0)编辑 收藏

C+之父力作学习笔记6——派生类

      现在来考虑做一个程序,处理某公司所雇佣人员的问题。这个程序可能包含如下一种数据结构:
struct Employee
{
    
string first_name,family_name;
    
char middle_initial;
    Date hiring_date;
    
short department;
    
//
}
;
下一步我们可能需要去定义经理:
struct Manager
{
    Employee emp;
    list
<Employee*> group; //所管理的人员
    short level;
    
//
}
;
一个经理同时也是一个雇员,所以在Manager对象的emp成员存储着Employee数据。很明显这样的设计是糟糕的,大家都会想到派生:
struct Manager:public Employee
{
    list
<Employee*> group;
    
short level;
}
;
这个Manager是由Employee派生的,反过来就是说,Employee是Manager的一个基类。类Manager包含类Employee得所有成员,再加上它自己的一些成员。
      按照这种方式从Employee派生出Manager,就使Manager成为Employee的一个子类型,使Manager可以用在能够接受Employee的任何地方。因为Manager是Employee,所以Manager*就可以当做Employee*使用。然而,因为Employee不一定是Manager,所以Employee*就不能当做Manager*用。总而言之类Derived有一个公用基类Base,那么就可以用Derived*给Base*类型的变量赋值,不需要显示的类型转换。而相反的方向,从Base*到Derived*则必须显示转换。例如:
void g(Manager mm,Employee ee)
{
    Employee
* pe = &mm;  //可以:Manager都是Employee
    Manager* pm = &ee;   //错误:Employee不一定是Manager
    pm->level = 2;       //灾难:ee没有level
    pm = static_cast<Manager*>(pe);//蛮力:这个可以,因为pe指向的是Manager mm
    pm->level = 2;       //没问题
}

      派生类的成员可以使用其基类的公用的和保护的成员,但是,派生类不能使用基类的私有成员。对于派生类的成年公园而言,保护成员就像是公用成员;但对于其他函数它们则像是私用成员。
      下面说说派生类的构造函数和析构函数
      有些派生类需要构造函数。如果某个基类中有构造函数,那么就必须调用这些构造函数中的某一个。默认构造函数可以被隐含的调用,但是,如果一个基类的所有构造函数都有参数,那么就必须显示的调用其中的某一个。基类构造函数的参数应在派生类构造函数的定义中有明确描述。在这方面,基类的行为恰恰就像是派生类的一个成员。例如:
Employee::Employee(const string& n,int d):family(n),department(d)
{
    
//
}


Manager::Manager(
const string& n,int d,int lvl):Employee(n,d),/*初始化基类*/level(lvl)/*初始化成员*/
{
    
//
}
派生类的构造函数只能描述它自己的成员和自己的直接基类的初始式,它不能直接去初始化基类的成员,例如:
Manager::Manager(const string& n,int d,int lvl):family_name(n).department(d),level(lvl)//错误:在Manager里没有family_name和department的声明
{
//
}
 类对象的构造是自下而上进行的:首先是基类,而后是成员,再后才是派生类本身。类对象的销毁则正好以相反的顺序进行:首先是派生类本身,而后是成员,再后才是基类。
      对于给定的一个类型为Base*的指针,被指的对象到底属于哪个派生类型呢?这个问题有四种基本的解决方案:
  1.  保证被指的只能是唯一类型的对象
  2. 在基类里安排一个类型域,供函数检查
  3.  使用dynamic_cast
  4.  使用虚函数  

       从Employee的函数中取得“正确的”行为i,而又不依赖于实际使用的到底是哪一种Employee,这就是所谓的多态性。一个带有虚函数的类型被称为是一个多态类型。要在C++里取得多态行为,被调用的函数就必须是虚函数,而对象则必须是通过指针或者引用去操作的。如果直接操作一个对象(而不是通过指针或引用),它的确切类型就已经为编译器所知,因此也就不需要运行时的多态性了。
      那么一个虚函数声明为纯虚函数,则这个虚函数所在的类为抽象类。用=0作为初始式就使虚函数成为“纯虚的”。注意:不能创建抽象类的对象。抽象类只能做界面,作为其他类的基类。还有一点也要指的注意,一个未在派生类里定义的纯虚函数仍旧还是一个纯虚函数,这种情况也将使该派生类仍为一个抽象类。例如:

class Shape
{
     
public:
        
virtual void draw()=0;
        
virtual bool isClose()=0;
     
//
}
;

class Circel:public Shape
{
    
public:
       
bool isClose(){return true;}//覆盖Shap::isClose
       
//draw尚未覆盖
}
;

Circel a;//错误:声明的是抽象类Circel对象

抽象类的最重要用途就使提供一个界面,而又不是暴露任何实现的细节。
      
     忠告 :

  • 避免类型域
  • 用抽象类将设计的中心集中到提供清晰的界面方面
  • 用抽象类使界面最小化
  • 一个有虚函数的类应该有一个虚析构函数
  • 抽象类通常不需要构造函数

posted @ 2011-08-28 17:20 Daywei 阅读(1968) | 评论 (0)编辑 收藏

C++之父力作学习笔记5——运算符重载

      在C++包含很多运算符,但以下几个运算符不能由用户定义:
      ::(作用域解析;)
      ,(成员选择)
      .* (通过到成员的指针做成员选择)
      ?:三元条件运算符
      sizeof和typeid

      运算符函数的名字是由关键字operator后跟对应的运算符构成的;例如operator<<。运算符函数的定义和使用都可以像其他函数一样。使用运算符不过是显示调用运算符函数的一种简写形式。例如
void f(complex a,complex b)
{
    complex c
=a+b;  //简写
    complex d=a.operator+(b);//显示调用
}


      一个运算符函数必须或者是一个成员函数,或者至少有一个用户定义类型的参数(重新定义运算符new和delete的函数则没有此项要求)。这一规则就保证了用户不能改变原有表达式的意义,除非表达式中包含有用户定义类型的对象。特别的,不能定义只对指针进行操作的运算符函数。

      忠告:
      1.定义运算符主要是为了模仿习惯使用方式
      2.对于大型运算对象,请使用const引用参数类型
      3.对于需要访问表示的操作,优先考虑作为成员函数而不是作为非成员函数
      4.对于对称的运算符采用非成员函数
      5.将只有一个“大小参数”的构造函数做成explicit

      运算符重载的内容应该还是挺多的,但却不知道如何写,看来还是文笔太差了,有机会再补上吧。
      

posted @ 2011-08-20 13:41 Daywei 阅读(1461) | 评论 (0)编辑 收藏

C++之父力作学习笔记(4)——类的好多事

      类,这个概念比较大。包含的事太多。咱们就一一的尽量弄清楚它。
      一个类就是一个用户定义类型。C++里类概念的目标就是为程序员提供一种建立新类型的工具,是这些新类型的使用能够像内部一样方便。
      访问控制:class成员的默认访问方式是私有的。一个struct也是一个class,但是其成员的默认方式是公用的。非成员函数禁止访问私有成员。
      构造函数:就是函数名和类名一样的函数且没有返回值。这谁都知道。It's easy。而默认构造函数就是调用时不必提供参数的构造函数。如果用户自己声明了一个默认构造函数,那么就会去使用它;否则,如果有必要,而且用户没有声明其他的构造函数,编译器就会设法去生成一个。编译器生成的默认构造函数将隐式地为类类型的成员和它的基类调用有关的默认构造函数。这里解释一下:类类型(Class type)即指那些由程序员定义的类而产生的类型,以便与内部类型和其他用户定义类型相区分。相信大家这里也没什么问题。有一个注意点来了,由于const和引用必须进行初始化,包含const或引用成员的类就不能进行默认构造,除非程序员的我们自己显示的提供默认构造函数。例如:
struct X
{
    
const int a;
    
const int& r;
}
;
X x;
//错误;X无默认构造函数
      默认构造函数也可以显示调用。内部类型同样也有默认构造函数。
      下面再谈谈复制构造函数,先看看复制构造函数是怎么引进来的。
按照默认约定,类对象可以复制。特别是可以用一个类的对象和复制对该类的其他对象进行初始化。即使是声明了构造函数的地方,也是可以这样做:
Date d=today;//通过复制初始化
按照默认方式,类对象的复制就是其中各个成员的复制。如果某个类X所需要的不是这种默认方式,那么就可以定义一个复制构造函数X::X(const X&),由它提供所需要的行为。还有一个概念就是复制赋值,很容易和复制构造函数搞混。咱们就一起搞清楚它们。先看一段程序:
void h()
{
    Table t1;
    Table t2
=t1;//复制初始化
    Table t3;
    t3
=t2;      //复制赋值
}
看似好像没什么问题,对于复制上面提到的解释方式,在应用到具有指针成员的类的对象时,就可能产生一种出人意料的作用。对于包含了由构造函数/析构函数管理的资源的对象而言,按成员复制的语义通常是不正确的。在这里,Table的默认构造函数为t1和t3各调用了一次,一共是两次。然而Table的析构函数则被调用了三次;对t1、t2和t3各一次!由于赋值的默认解释是按成员赋值,所以在h()结束时,t1、t2和t3中将各包含一个指针,它们都指向建立t1时从自由存储中分配的那个名字数组。在建立t3时所分配的数组的指针并没有保留下来,因为它被赋值t3=t2覆盖掉了。这样,如果没有自动废料收集,对这个程序而言,该数组的存储就将永远丢掉了。而在另一方面,为t1的创建而分配的数组因为同时出现在t1、t2和t3里,将被删除3次。这种情况所导致的结果是无定义,很可能是灾难性的。这类反常情况可以避免,方式就是将Table复制的意义定义清楚:
class Table
{
    
//---
    Table(const Table&);//复制构造函数
    Table& operator=(const Table&);//复制赋值
}
;
咱们自己可以为这些复制操作定义自己认为最合适的任何意义,例如
//这里补上Table类的详细定义
class Table
{
    Name
* p;
    size_t sz;
public:
    Table(size_t s
=15)
    
{
        p
=new Name[sz=s];
    }

    
~Table()
    

        delete[] p;
    }

    Name
* loopup(const char*);
    
bool insert(Name*);
}


Table::Table(
const Table& t)//复制构造函数
{
   p
=new Name[z=t.sz];
   
for(int i=0;i<sz;i++)
      p[i]
=t.p[i];
}


Table
& Table::operator=(const Table& t)//赋值
{
    
if(this!=&t)//当心自赋值:t=t
    
{
        delete[] p;
        p
=new Name[sz=t.sz];
        
for(int i=0;i<sz;i++)
            p[i]
=t.p[i];
    }

    
return *this;
}
情况几乎总是如此,复制构造函数与复制赋值通常都很不一样。究其根本原因,复制构造函数是去完成对为初始化的存储区的初始化,而复制赋值运算符则必须正确处理一个结构良好的对象。
      成员常量:
      对那些静态整型成员,可以给它的成员声明加上一个常量表达式作为初始式,例如
class Curious
{
    
static const int c1=7;//ok,但要记得去定义
    static int c2=11;//错误:非const
    const int c3;//错误:非Static
    static const int c4=f(1);//错误:在类里的初始表达式不是常量
    static const float c5=7.0;//错误:在类里初始化的不是整型
}
1)在类中不能用const来创建常量!因为:类只是描述了对象的形式,并没有真正创建对象!所以, 在对象建立之前,并没有存值空间!
2)而const是用来创建常量的!
方法1 你可以用枚举:
class a
{
enum{buf_size_t buf_size=、、、}//用枚举创建一个常量,但不是数据成员

}

方法2 你可以用static
class a
{
private
  
static const buf_size_t buf_size=30//该常量将与憋得静态常量存储在一起,而不是存储在对象中
}
但《C++程序设计语言》书上说当你用到某个被初始化的成员,而且需要将它作为对象存入存储器时,这个成员就必须在某处有定义。初始式不必重复写:
const int Curious::c1;//必须,但这里不必重复初始式
const int* p=&Cusious::c1;//ok:Curious::c1已经有定义
这里有点让我懵了,为什么还要const int Curious::c1;//必须,但这里不必重复初始式 这一行呢?还说是必须,经过测试是有问题的——当前范围内的定义或重新声明非法,到底是书错了还是还有其他什么原因?
还请高手不吝赐教
今天就到这里吧,到这里就出了问题,还需要思考。

这里有一篇博文关于
VC6.0中,整型const static成员不能在类的定义体中初始化. http://blog.csdn.net/yiruirui0507/article/details/5984530




posted @ 2011-08-05 17:00 Daywei 阅读(2202) | 评论 (0)编辑 收藏

C++之父力作学习笔记3——指针

   由于工作需要转成了C#,好久没有学C++了,之前学了一段时间的C++,也写过两篇,放在博客园里的,现在有专门的C++博客,以后就在这里写了。以下是前两篇的地址
C++之父力作学习笔记1    C++之父力作学习笔记
    
   今天来简单说一下指针,可以说指针是一个难点,是一把双刃剑,也许高手才能运用自如,像我这样的菜鸟就会伤到自己。呵呵,废话少说。
   指针:对类型T,T*是“到T的指针”,也就是说,一个类型为T*的变量能保存一个类型T的对象的地址。例如:
char c='a';
char *p=&c;//p保存着c的地址

用图表示是:

这些都挺容易理解的,不幸的是,到数组的指针和到函数的指针需要更复杂的记法:
int* pi;          //到int的指针
char** ppc;       //到字符的指针的指针
int* ap[10];      //10个到int的指针的数组
int (*fp)(char*); //到函数的指针,这种函数以char*为参数,返回int
int* f(char*);    //有一个char*参数的函数,返回一个到ini的指针

   对指针的基本操作是间接引用,也就是说引用被指针所指的那个对象。这一操作也被称作间接(indirectionn)。间接运算符是(前缀的)一元*。例如
char c='a';
char* p=&c;   //p保存着c的地址
char c2=*p;   //c2=='a'
被p所指的变量是c,而c中所存的值是'a'。所以由*p赋给c2的值就是'a'.
注意:这里解释一下 间接运算符是(前缀的)一元*。这就要扯到声明的结构了。
         一个声明由四个部分组成:一个可选的“描述符”,一个基础类型,一个声明符,还有一个可选的初始式。除了函数和名字空间之外,其他声明都应该由分号结束。例如:
char* kings[]={"Antigonus","Seleucus","Ptolemy"};
这里的基础类型是char,声明符是*kings[],而初始化是={...}。
      描述符是一个开始关键字,例如:virtual和extern,它们说明了被声明事物的某些非类型的属性。
      声明符由一个名字和可选的若干声明运算符组成。最常用的声明运算符是
      *             指针          前缀
      *const     常量指针     前缀
      &            引用           前缀
      []            数组          后缀
      ()            函数          后缀




posted @ 2011-07-26 11:13 Daywei 阅读(2525) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿

随笔分类

随笔档案

文章档案

牛人博客

搜索

积分与排名

最新评论

阅读排行榜