13.3.4 关于结构的补充细节
这里应该提到定义结构时有一些灵活性。首先,将变量定义为特定结构类型的同时,声明这个结构是合法的。只需要将变量名称放在结构定义的终止分号之前即可。比如,表达式
struct date
{
int month;
int day;
int year;
}todaysDate, purchaseDate;
定义了date结构,同时也声明了变量todaysDate和purchaseDate为这个类型。还可以按常规方式来给变量赋初值。因此
struct date
{
int month;
int day;
int year;
}todaysDate={9,25,2010};
定义了date结构,同时也将变量todaysDate赋予如上初值。
如果定义结构时,也定义了该结构类型的所有变量,那么可以省略结构名称。所以表达式
struct
{
int month;
int day;
int year;
}dates[100];
定义了包含100个元素的数组dates。每个元素都是包含月、日和年三个整型成员的结构。因为</p>
没有为这个结构提供名称,所以定义同类型变量的唯一方式就是再次显式地定义这个结构。
位字段
在Objective-C语言中有两种包装信息的方式。一种方式是在整数内表示这些数据,然后使用第4章“数据类型和表达式”中提到的位运算符来访问所需的位。
另一种方式是用Objective-C语言所谓的位字段(bit field)来定义包装信息的结构。这种方法在定义结构时用到了特殊语法,它允许定义一个位字段并给该字段指定名称。
要定义位字段,可以定义一个名为packedStruct的结构,比如:
struct packedStruct
{
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int type:4;
unsigned int index:9;
};
结构packedStruct定义为包含5个成员。第一个成员名为f1,是unsigned int。成员名称之后的:1表示这个成员将占用1位。类似地,标志f2和f3定义为1位。成员type被定义占用4位,而成员index定义为9位。
编译器自动地将前面的位字段定义包装在一起。这种方式好的方面是定义为packedStruct类型的字段变量可以和一般结构成员那样进行访问。所以,如果如下声明一个名为packedData的变量:
struct packedStruct packedData;
那么,可以使用这个简单的表达式方便地将packedData中的type字段设置为7:
packedData.type=7;
还可以使用类似的表达式将该字段赋值为n:
packedData.type=n;
后面这种情况,不必考虑n的值对于type字段是否过大,只有n的低4位赋值给packedData.type。
从位字段中提取数值同样也是自动执行的,所以语句
n=packedData.type;
提取packedData的type字段(自动根据需要将它移到低位)并将之赋给n。
位字段可以用在正则表达式中,并且自动转换成整型数据。因此语句
i=packedData.index/5+1;
是完全合法的,下面的表达式也一样:
if(packedData.f2)
……
这个语句测试标志f2是开还是关。关于位字段值得注意的一个事项是:不能保证字段在内部赋值时是从左到右还是从右到左。因此,如果位字段是从右向左赋值,那么f1将位于最低位,f2位于f1左边的位置,依此类推。除非处理由不同程序或其他机器产生的数据,否则这并不会产生问题。
还可以在包含位字段的结构中包含正常的数据类型。因此,如果想要定义包含一个int、一个char和两个1位标志的结构,下面的定义是合法的:
struct table_entry
{
int count;
char c;
unsigned int f1:1;
unsigned int f2:1;
};
位字段在结构定义中被包装成单位(units),单位的大小由实现来定义,并且最可能是一个字大小。Objective-C编译器并不会因为尝试优化存储空间,而重新组织位字段定义。
可以指定没有名称的位字段来跳过字中的某些位,比如下面的语句
struct x_entry
{
unsigned int type:4;
unsigned int:3;
unsigned int count:9;
};
定义了一个x_entry结构,它包含一个名为type的4位字段和一个名为count的9位字段。未命名的字段表示分开type和count字段的3个位。
字段规范的最后一点涉及到长度为0的未命名字段这一特殊情况。它可以用来强制调整结构中的下一个字段作为单位边界的开始点。