发布新日志

  • C语言基础--标识符的作用域

    2008-03-10 10:39:39

    一个标识符的作用域(scope)指的是“翻译单元的一部分”,并且在此处,标识符是有意义的。或者,换句话说,标识符的作用域是程序中可以“看到”该标识符的代码部分。作用域的类型由“声明标识符的位置”决定(但卷标标识符是例外,卷标一定具有函数的作用域)。有四种可能的作用域:

    文件作用域

    如果声明标识符的地方位于任何语句块和参数列表之外,那么此标识符就拥有文件作用域。可以在声明后的任何地方(且在翻译单元结束之前)使用此标识符。

    语句块作用域

    在语句块内声明的标识符具有语句块作用域,但标签是例外。这样的标识符只能出现在从“声明处”到“包含此声明的最小语句块的结尾”。最小的包含语句块常常是某个函数的定义。在C99中,声明不一定要放在函数体内所有的语句之前。在一个函数定义的“头部”内出现的“参数名称”,也具有语句块作用域,而且在整个函数体内都有效。

    函数原型作用域

    函数原型内的参数名称具有函数原型作用域。这些参数名称在原型外面不重要,所以它们只有注释的意义。

    函数作用域

    一个标签的作用域一定在该标签所处的函数体内,即使它被放在嵌套的语句块内也是一样。换句话说,可以使用goto语句,从任意点跳到同一个函数内的某个标签处(但是,跳进被嵌套的语句块的做法不好)

    标识符的作用域通常从声明之后开始,然而类型名称,或者结构,联合,枚举类型的小标签,以及枚举常量名称,都是例外:当它们出现在声明中,他们的作用域就立刻开始,所以他们可以在声明中再次被引用。比方说,在下面的结构声明中,结构的最后一个成员next是一个指针,指向正在声明的结构类型本身:

    struct Node{/*...*/  struct Node *next;};//定义一个结构类型

    void printNode(const struct Node*ptrNode);//声明一个函数

    int printList(const struct Node*first)//这是一个函数定义

    {

    struct Node *ptr=first;

    while(ptr!=NULL){

    printNode(ptr);

    ptr=ptr->next;

    }

    }

    在这个程序代码片段中,标识符Node、next、printNode、printList都具有文件作用域。参数ptrNode具有函数原型作用域,而变量first和ptr具有语句块作用域。

    在既有作用域内的一个嵌套的新声明中,可以重复使用一个标识符,只不过这个新的标识符并没有不同的命名空间。如果真的这么做,那么此新的声明一定会具有语句块作用域或者函数原型作用域,而此语句块作用域或者函数原型作用域一定是外面作用域的子集。在这样的例子中,相同标识符的新声明会将外面的声明隐藏起来,而内部的作用域无法看见外面语句块中所声明的变量或函数。例如,下面的声明是可行的。

    double x;//声明一个变量x,具有文件作用域

    long calc(double x);//声明一个新的x,具有函数原型作用域

    int main()

    {

    long x=calc(2.5);//声明一个long变量x,具有语句块作用域

    if(x<0)//x是long变量

    {float x=0.0f;//声明一个新的浮点变量x,具有语句块作用域

    /*...*/

    }

    x*=2;//x还是long变量

    /*...*/

    }

     

  • C语言基础__通用字符名称

    2008-03-10 09:11:07

    C语言也支持把通用字符名称(universal character name)作为使用扩展字符集的方法,而不管C的实现版本采用何种编码.可以使用通用字符名称指定扩展字符,而通用字符名称就是其Unicode的值,格式如下.

    \uxxxx或者\UXXXXXXXX

    其中XXXX或XXXXXXXX是十六进制表示法的Unicode码点(code point,指的是码集合内的一个码).小写的u后面接着四个十六进制数字,或者大写的U后面接着正好八个十六进制数字.如果某个码点前四个十六进制数字是零,那么其通用字符名称写成\uXXXX或\U0000XXXX都可以.

    通用字符名称可以用于标识符、字符常量、字符串字面值中。然而,通用字符名称不可以用于表示基本字符集内的字符。

    当用通用字符名称的方式表示一个字符的时候,编译器会将其存储在实现版本所使用的字符集内。比方说,如果一个本土化(localized)程序内的运行字符集是ISO8859-7(8位希腊),那么下列的定义将变量alpha的值初始化位\xE1的码:

    char alpha='\u03B1';

    然而,如果此运行字符集是UTF-16,需要将此变量定义成一个宽字符:

    wchar_t alpha='\u03B1';

    在这个例子中,被赋值到alpha的字符码值是十六进制的3B1,和通用字符名称一样。

    注意:有的编译器不支持通用字符名称。

  • C语言基础__宽字符和多字节字符

    2008-03-07 12:12:36

    C语言原本是在英文环境中设计的,主要的字符集是7位的ASCII码.从此开始,8位的byte(字节)变成最常见的字符编码单位,但是国际化软件必须能够表示不同的字符,而这些字符数量庞大,无法使用一个字节编码,于是世界上使用各式各样多字节的字符编码集合已经数十年了,比如用来表示"非拉丁字母"以及"非字母"的中,日,韩文字系统.在1994年,"Normative Addendum1"(基准增补一)的采用,让ISO C可以标准化两种表示大型字符集的方法:宽字符(wide character,该字符集内每个字符使用相同的位长)以及多字节字符(multibyte chatacter,每个字符可以是一到多个字节不等,而某个字节序列的字符的字符值由字符串或流(stream)所在的环境背景决定). 注意:虽然C现在提供抽象机制,可以处理和转换不同种类的编码集合,但语言本身并没有定义或指定任何编码集合,或任何字符集. 自从1994年的增补之后,C不只提供char类型,还提供wchar_t类型(宽字符),此类型定义在stddef.h头文件中.wchar_t类型足以表示某个实现版本扩展字符集的任何元素. 虽然C标准没有支持Unicode字符集,许多实现版本使用Unicode转换格式UTF-16和UTF-32(参考http://www.unicode.org)来处理宽字符.Unicode标准和ISO/IEC 10646标准相当接近,而且是许多既有字符集(包括7位的ASCII)的超集.如果遵循Unicode标准,wchar_t类型至少是16或32位长,而wchar_t类型的一个值就代表一个Unicode字符.比方说,下列的定义将变量wc初始化为希腊字母a. wchar_t wc = '\x3b1'; 此转义符以"\x"起头,后面接着十六进制的数字,会将这个数字所代表的字符赋值到变量中.在这个例子中,此字符是小写的alpha 在多字节字符集中,每个字符的编码宽度都不等,可以是一个字节,可以是一个字节,也可以是多个字节.源代码字符集和运行字符集都可能包含多字节字符,如果真的包含多字节字符的话,那么基本字符集中的每个字符都只会占用一个字节(完全没有多字节的字符),空字符是唯一的例外,空字符可能会占用任意个数的字节(但这些字节内全部的位都必须是0).多字节字符可以被用于字符的常量,字符串字面值,标识符,注释,以及头文件.许多的多字节字符集被设计来支持特定国家语言,例如JIS字符集(日本业界标准).多字节UTF-8字符集是由Unicode Consortium(万国码联盟)定义的,可以表示Unicode字符集的所有字符.UTF-8字符所使用的空间大小从一个字节到四个字节都有可能. 多字节字符和宽字符(也就是wchar_c)的主要差异在于宽字符占用的字节数目都一样,而多字节字符的字节数目不等,这样的表示方式使得多字节字符串比宽字符串更难处理.比方说,即使字符'A'可以用一个字节来表示,但是要在多字节的字符串中找到此字符,就不能使用简单的字节比对,因为即使在某个位置找到相符合的字节,此字节也不见得是一个字符,它可能是另一个不同字符的一部分.然而,多字节字符相当适合用来将文字储存成文件. C提供了一些标准函数,可以将多字节字符转换为wchar_t,或将宽字符转换为多字节字符.比方说,如果C编译器使用Unicode标准的UTF-8和UTF-16,那么下面调用wctomb()函数就可以获得字符a的多字节表示方式(注:wctomb=wide character to multibyte).

    wchar_t wc=L'\x3B1';

    char mbStr[10]=" ";

    int bBytes=0;

    nBytes=wctomb(mbStr,wc);

    在调用此函数之后,mbStr数组会得到多字节的字符,在这个例子中,也就是"\XCE\XB1"符号.此函数返回值是"所需要的字节个数",在这个例子中,被赋值到变量nByptes的值是2,意思是:希腊小写字母alpha在多字节中需要占两个字符.

Open Toolbar