3.4 数据类型和常量

知识点讲解光盘:视频\知识点\第3章\数据类型和常量.mp4

其实在本章前面的第一段代码中已经接触过Objective-C的基本数据类型int,例如声明为int类型的变量只能用于保存整型值,也就是说没有小数位的值。其实除了int类型之外,在Objective-C还有另外3种基本数据类型,分别是float、double和char,具体说明如下所示。

❑float:用于存储浮点数(即包含小数位的值)。

❑double:和float类型一样,但是前者的精度约是后者精度的两倍。

❑char:可以存储单个字符,例如字母a、数字字符100,或者一个分号“;”。

在Objective-C程序中,任何数字、单个字符或者字符串通常被称为常量。例如,数字88表示一个常量整数值。字符串@“Programming in Objective-C”表示一个常量字符串对象。在Objective-C程序中,完全由常量值组成的表达式被称为常量表达式。例如下面的表达式就是一个常量表达式,因为此表达式的每一项都是常量值。

        128 + 1-2

如果将i声明为整型变量,那么下面的表达式就不是一个常量表达式。

        128 + 1- i

在Objective-C中定义了多个简单(或基本)的数据类型,例如int表示整数类型,这就是一种简单的数据类型,而不是复杂的对象。

注意:虽然Objective-C是一门面向对象的语言,但是简单数据类型并不是面向对象的。它们类似于其他大多数非面向对象语言(比如C语言)的简单数据类型。在Objective-C中提供简单数据类型的原因是出于效率方面的考虑,另外,与Java语言不同,Objective-C的整数大小根据执行环境的觃定而变化。

3.4.1 int类型

在Objective-C程序中,整数常量由一个或多个数字的序列组成。序列前的负号表示该值是一个负数,例如值88、-10和100都是合法的整数常量。Objective-C规定,在数字中间不能插入空格,并且不能用逗号来表示大于999的值。所以数值“1,200”就是一个非法的整数常量,如果写成“1200”就是正确的。

在Objective-C中有两种特殊的格式,它们用一种非十迚数(基数10)的基数来表示整数常量。如果整型值的第一位是0,那么这个整数将用八迚制计数法来表示,就是说用基数8来表示。在这种情况下,该值的其余位必须是合法的8迚制数字,因此必须是0到7之间的数字。因此,在Objective-C中以8迚制表示的值50(等价于10迚制的值40),表示方式为050。与此类似,八迚制的常量0177表示十迚制的值127(1×64+7×8+7)。通过在NSLog调用的格式字符串中使用格式符号%o,可以在终端上用八迚制显示整型值。在这种情况下,使用八迚制显示的值不带有前导0。而格式符号%#o将在八迚制值的前面显示前导0。

如果整型常量以0和字母x(无论是小写字母还是大写字母)开头,那么这个值都将用十六迚制(以16为基数)计数法来表示。紧跟在字母x后的是十六迚制值的数字,它可以由0到9之间的数字和a到f(或A到F)之间的字母组成。字母表示的数字分别为10到15。假如要给名为RGBColor的整型常量指派十六迚制的值FFEF0D,则可以使用如下代码实现。

        RGBColor = 0xFFEF0D;

在上述代码中,符号“%x”用十六迚制格式显示一个值,该值不带前导的0x,并用a到f之间的小写字符表示十六迚制数字。要使用前导0x显示这个值,需要使用格式字符%#x的帮助,例如下面的代码。

        NSlog("Color is %#x\n", RGBColor);

在上述代码中,通过“%X”或“%#X”中的大写字母X可以显示前导的x,然后用大写字母表示十六迚制数字。无论是字符、整数还是浮点数字,每个值都有与其对应的值域。此值域与存储特定类型的值而分配的内存量有关。在大多数情况下,在Objective-C中没有规定这个量,因为它通常依赖于所运行的计算机,所以叫做设备或机器相关量。例如,一个整数不但可以在计算机中占用32位空间,而且也可以使用64位空间来存储。

另外,在任何编程语言中,都预留了一定数量的标识符,这些标识符是不能被定义变量和常量的。下面的表3-2中列出了Objective-C程序中具有特殊含义的标识符。

表3-2 特殊的预定义标识符

3.4.2 float类型

在Objective-C程序中,float类型变量可以存储小数位的值。由此可见,通过查看是否包含小数点的方法可以区分出是否是一个浮点常量。在Objective-C程序中,不但可以省略小数点之前的数字,而且也可以省略之后的数字,但是不能将它们全部省略。例如3.、125.8及-.0001等都是合法的浮点常量。要想显示浮点值,可用NSLog转换字符——%f。

另外,在Objective-C程序中也能使用科学计数法来表示浮点常量。例如“1.5e4”就是使用这种计数法来表示的浮点值,它表示值1.5×104。位于字母e前的值称为尾数,而之后的值称为指数。指数前面可以放置正号或负号,指数表示将与尾数相乘的10的幂。因此,在常量2.85e-3中,2.85是尾数值,而-3是指数值。该常量表示值2.85×10-3,或0.00285。另外,在Objective-C程序中,不但可用大写字母书写用于分隔尾数和指数的字母e,而且也可以用小写字母来书写。

在Objective-C程序中,建议在NSLog格式字符串中指定格式字符%e。使用NSLog格式字符串%g时,允许NSLog确定使用常用的浮点计数法还是使用科学计数法来显示浮点值。当该值小于-4或大于5时,采用%e(科学计数法)表示,否则采用%f(浮点计数法)。

十六迚制的浮点常量包含前导的0x或0X,在后面紧跟一个或多个十迚制或十六迚制数字,然后紧接着是p或P,最后是可以带符号的二迚制指数。例如,0x0.3p10表示的值为3/16×210=192。

3.4.3 double类型

在Objective-C程序中,类型double与类型float类似。Objective-C规定,当在float变量中所提供的值域不能满足要求时,需要使用double变量来实现需求。声明为double类型的变量可以存储的位数,大概是float变量所存储的两倍多。在现实应用中,大多数计算机使用64位来表示double值。除非另有特殊说明,否则Objective-C编译器将全部浮点常量当作double值来对待。要想清楚地表示float常量,需要在数字的尾部添加字符f或F,例如:

        12.4f

要想显示double的值,可以使用格式符号%f、%e或%g来辅助实现,它们与显示float值所用的格式符号是相同的。其实double类型和float类型可以被称为实型。在Objective-C语言中,实型数据分为实型常量和实型变量。

1.实型常量

实型常量也称为实数或者浮点数。在Objective-C语言中,它有两种形式:小数形式和指数形式。

❑小数形式:由数字0~9和小数点组成。例如:0.0、25.0、5.789、0.13、5.0、300.和-267.8230等均为合法的实数。注意,必须有小数点。在NSLog上,使用%f格式来输出小数形式的实数。

❑指数形式:由十迚制数,加阶码标志“e”或“E”以及阶码(只能为整数,可以带符号)组成。其一般形式为:a E n(a为十迚制数,n为十迚制整数)。其值为a*10n。在NSLog上,使用%e格式来输出指数形式的实数。例如下面是一些合法的实数。

        2.1E5(等于2.1*105)
        3.7E-2(等于3.7*10-2)

而下面是不合法的实数。

        345(无小数点)
        E7(阶码标志E 之前无数字)
        -5(无阶码标志)
        53.-E3(负号位置不对)
        2.7E(无阶码)

Objective-C允许浮点数使用后缀,后缀为“f”或“F”即表示该数为浮点数。如356f和356F是等价的。

2.实型变量

(1)实型数据在内存中的存放形式

实型数据一般占4个字节(32位)内存空间,按指数形式存储。小数部分占的位(bit)数越多,数的有效数字越多,精度越高。指数部分占的位数越多,则能表示的数值范围越大。

(2)实型变量的分类

实型变量分为:单精度(float型)、双精度(double型)和长双精度(long double型)3类。在大多数机器上,单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供7位有效数字。双精度型占8个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。

3.4.4 char类型

在Objective-C程序中,char类型变量的功能是存储单个字符,只要将字符放到一对单引号中就能得到字符常量。例如‘a'、‘;’和‘0’都是合法的字符常量。其中‘a’表示字母a,‘;’表示分号,‘0’表示字符0(并不等同于数字0)。

在Objective-C程序中,不能把字符常量和C风格的字符串混为一谈,字符常量是放在单引号中的单个字符,而字符串则是放在双引号中任意个数的字符。不但要求在前面有@字符,而且要求放在双引号中的字符串才是NSString字符串对象。

另外,字符常量‘\n'(即换行符)是一个合法的字符常量,虽然这看似与前面提到的规则相矛盾。出现这种情况的原因是,反斜杠符号是Objective-C中的一个特殊符号,而其实并不把它看成一个字符。也就是说,Objective-C编译器仅仅将‘\n’看作是单个字符,尽管它实际上由两个字符组成,而其他的特殊字符由反斜杠字符开头。

在NSLog调用中,可以使用格式字符%c来显示char变量的值。例如在下面程序代码中,使用了基本的Objective-C数据类型。

        #import <Foundation/Foundation.h>
        int main (int argc, char *argv[])
        {
            NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
            int     integerVar = 50;
            float  floatingVar = 331.79;
            double doubleVar = 8.44e+11;
            char    charVar = 'W';
            NSLog (@"integerVar = %i", integerVar);
            NSLog (@"floatingVar = %f", floatingVar);
            NSLog (@"doubleVar = %e", doubleVar);
            NSLog (@"doubleVar = %g", doubleVar);
            NSLog (@"charVar = %c", charVar);
            [pool drain];
            return 0;
        }

在上述代码中,第六行floatingVar的值是331.79,但是,实际显示为331.790009。这是因为,实际显示的值是由使用的特定计算机系统决定的。出现这种不准确值的原因是计算机内部使用特殊的方式表示数字。当使用计算器处理数字时,很可能遇到相同的不准确性。如果用计算器计算1除以3,将得到结果.33333333,很可能结尾带有一些附加的3。这串3是计算器计算1/3的近似值。理论上,应该存在无限个3。然而该计算器只能保存这些位的数字,这就是计算机的不确定性。此处应用了相同类型的不确定性:在计算机内存中不能精确地表示一些浮点值。

执行上述代码后会输出。

        integerVar = 50
        floatingVar = 331.790009
        doubleVar = 8.440000e+11
        doubleVar = 8.44e+11
        charVar = ‘W’

另外,使用char也可以表示字符变量。字符变量类型定义的格式和书写规则都与整型变量相同,例如下面的代码。

        char a, b;

每个字符变量被分配一个字节的内存空间,因此只能存放一个字符。字符值是以ASCII码的形式存放在变量的内存单元之中的。如x的十迚制ASCII码是120,y的十迚制ASCII码是121。下面的例子是把字符变量a、b分别赋予‘x’和‘y'。

        a='x';
        b='y';

实际上是在a、b两个内存单元内存放120和121的二迚制代码。我们可以把字符值看成是整型值。Objective-C语言允许对整型变量赋以字符值,也允许对字符变量赋以整型值。在输出时,允许把字符变量按整型量输出,也允许把整型量按字符量输出。整型量为多字节量,字符量为单字节量,当整型量按字符型量处理时,只有低8位字节参与处理。

3.4.5 字符常量

在Objective-C程序中,字符常量是用单引号括起来的一个字符,例如下面列出的都是合法字符常量。

        'a'、'b'、'='、'+'、'? '

Objective-C中的字符常量有如下4个特点。

(1)字符常量只能用单引号括起来,不能用双引号或其他括号。

(2)字符常量只能是单个字符,不能是字符串,转义字符除外。

(3)字符可以是字符集中任意字符。但数字被定义为字符型之后就不能参与数值运算。如‘5’和5是不同的。‘5’是字符常量,不能参与运算。

(4)Objective-C中的字符串不是“abc”,而是@“abc”。

转义字符是一种特殊的字符常量。转义字符以反斜线“\”开头,后面紧跟一个或几个字符。转义字符具有特定的含义,不同于字符原有的意义,故称“转义”字符。例如,“\n”就是一个转义字符,表示“换行”。转义字符主要用来表示那些用一般字符不便于表示的控制代码。常用的转义字符及其含义如表3-3所示。

表3-3 常用的转义字符及其含义

在大多数情况下,Objective-C字符集中的任何一个字符都可以使用转义字符来表示。ddd和hh分别为八迚制和十六迚制的ASCII代码,表中的\ddd和\xhh正是为此而提出的。例如\101表示字母A,\102表示字母B,\134表示反斜线,\XOA表示换行等。

        #import <Foundation/Foundation.h>
        int main(int argc, const char * argv[])
        {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
        char a=120;
        char b=121;
        NSLog(@"%c, %c", a, b);
        NSLog(@"%i, %i", a, b);
        [pool drain];
        return 0;
        }

在上述代码中,定义a、b为字符型,但在赋值语句中赋以整型值。从结果看,输出a和b值的形式取决于NSLog函数格式串中的格式符。当格式符为“%c”时,对应输出的变量值为字符,当格式符为“%i”时,对应输出的变量值为整数。执行上述代码后输出。

        x, y
        120,121

3.4.6 id类型

在Objective-C程序中,id是一般对象类型,id数据类型可以存储任何类型的对象。例如在下面的代码中,将number声明为id类型的变量。

        id number;

我们可以声明一个方法,使其具有id类型的返回值。例如在下面的代码中,声明了一个名为newOb的实例方法,它不但具有名为type的单个整型参数,而且还具有id类型的返回值。在此需要注意,对返回值和参数类型声明来说,id是默认的类型。

        -(id) newOb: (int) type;

再例如在下面的代码中,声明了一个返回id类型值的类方法。

        +allocInit;

id数据类型是本书经常使用的一种重要数据类型,是Objective-C中的一个十分重要的特性。表3-4列出了基本数据类型和限定词。

表3-4 Objective-C的基本数据类型

在Objective-C程序中,id类型是一个独特的数据类型。在概念上和Java语言中的类Object相似,可以被转换为任何数据类型。也就是说,在id类型变量中可以存放任何数据类型的对象。在内部处理上,这种类型被定义为指向对象的指针,实际上是一个指向这种对象的实例变量的指针。例如下面定义了一个id类型的变量和返回一个id类型的方法。

        id anObject;
        - (id) new: (int) type;

id和void *并非完全一样,下面是id在objc.h中的定义。

        typedef struct objc_object {
        class isa;
        } *id;

由此可以看出,id是指向struct objc_object的一个指针。也就是说,id是一个指向任何一个继承了Object或NSObject类的对象。因为id是一个指针,所以在使用id的时候不需要加星号,例如下面的代码。

        id foo=renhe;

上述代码定义了一个renhe指针,这个指针指向NSObject的任意一个子类。而“id*foo= renhe;”则定义了一个指针,这个指针指向另一个指针,被指向的这个指针指向NSObject的一个子类。

3.4.7 限定词

在Objective-C程序中的限定词有:long、long long、short、unsigned及signed。

1.long

如果直接把限定词long放在声明int之前,那么所声明的整型变量在某些计算机上具有扩展的值域。例如下面是一个上述情况的例子。

        long int factorial;

通过上述代码,将变量fractorial声明为long的整型变量。这就像float和double变量一样,long变量的具体精度也是由具体的计算机系统决定。在许多系统上,int与long int具有相同的值域,而且任何一个都能存储32位宽(231-1或2147483647)的整型值。

在Objective-C程序中,long int类型的常量值可以通过在整型常量末尾添加字母L(大小写均可)来形成,此时在数字和L之间不允许有空格出现。根据此要求,我们可以声明为如下格式。

        long int numberOfPoints = 138881100L;

通过上述代码,将变量numberOfPoints声明为long int类型,而且初值为138881 100。

要想使用NSLog显示long int的值,需要使用字母l作为修饰符,并且将其放在整型格式符号i、o和x之前。这意味着格式符号%li用十迚制格式显示long int的值,符号%lo用八迚制格式显示值,而符号%lx则用十六迚制格式显示值。

2.long long

例如在下面的代码中,使用了long long的整型数据类型。

        long long int maxnum;

通过上述代码,将指定的变量声明为具有特定扩展精度的变量,通过扩展精度,保证了变量至少具有64位的宽度。NSLog字符串不使用单个字母l,而使用两个l来显示long long的整数,例如“%lli”的形式。我们同样可以将long标识符放在double声明之前,例如下面的代码。

        long double CN_NB_2012;

可以long double常量写成其尾部带有字母l或L的浮点常量的形式,例如:

        1.234e+5L

要想显示long double的值,需要使用修饰符L来帮助实现。例如通过%Lf用浮点计数法显示long double的值,通过%Le用科学计数法显示同样的值,使用%Lg告诉NSLog在%Lf和%Le之间任选一个使用。

3.short

如果把限定词short放在int声明之前,意思是告诉Objective-C编译器要声明的特定变量用来存储相当小的整数。使用short变量的主要好处是节约内存空间,当程序员需要大量内存,而可用的内存又十分有限时,可以使用short变量来解决内存不足的问题。

在很多计算机设备上,short int所占用的内存空间是常规int变量的一半。在任何情况下,需要确保分配给short int的空间数量不少于16位。

在Objective-C程序中,没有其他方法可显示编写short int型常量。要想显示short int变量,可以将字母h放在任何普通的整型转换符号之前,例如%hi、%ho或%hx。也就是说,可以用任何整型转换符号来显示short int,原因是当它作为参数传递给NSLog例程时,可以转换成整数。

4.unsigned

在Objective-C程序中,unsigned是一种最终限定符,当整数变量只用来存储正数时可以使用最终限定符。例如通过下面的代码向编译器声明,变量counter只用于保存正值。使用限制符的整型变量可以专门存储正整数,也可以扩展整型变量的精度。

        unsigned int counter;

将字母u(或U)放在常量之后,可以产生unsigned int常量,例如下面的代码。

        0x00ffU

在编写整型常量时,可以组合使用字母u(或U)和l(或L),例如下面的代码可以告诉编译器将常量10000看作unsigned long。

        10000UL

如果整型常量之后不带有字母u、U、l或L中的任何一个,而且因为太大不适合用普通大小的int表示,那么编译器将把它看作是unsigned int值。如果太小则不适合用unsigned int来表示,那么此时编译器将把它看作long int。如果仍然不适合用long int表示,编译器会把它作为unsigned long int来处理。

在Objective-C程序中,当将变量声明为long int、short int或unsigned int类型时,可以省略关键字int,为此,变量unsigned counter和如下声明格式等价。

        unsigned counter;

同样也可以将变量char声明为unsigned。

5.signed

在Objective-C程序中,限定词signed能够明确地告诉编译器特定变量是有符号的。signed主要用在char声明之前。

3.4.8 总结基本数据类型

在Objective-C程序中,可以使用以下格式将变量声明为特定的数据类型。

          type name = initial_value;

在表3-5中,总结了Objective-C中的基本数据类型。

表3-5 Objective-C中的基本数据类型