结构

struct {
      int a;
      char  b;
      float  c;
} x;
这个声明创建了一个名叫x的变量。它包含三个成员:一个整数,一个字符和一个浮点数。
<pre name="code" class="cpp">struct {
int a;
int b;
float c;
} y[20], *z;
 
这个声明创建了y和z.y是一个数组,它包含了20个结构。z是一个指针,它指向这个类型的结果。
警告:
这个两个声明被编译器当做截然不同的类型,即使它们的成员列表完全相同。因此,变量y和z的类型和x的类型不同,所以下面这条语句
z = &x;
是非法的。
声明结构是可以使用另外一种良好技巧是用tyoedef创建一种新的类型,如下:
<pre name="code" class="cpp">typedef struct{
int a;
char b;
float c;
} Simple;
 
这个技巧和声明一个结构标签的效果几乎相同。区别在于Simple现在是个类型名而不是个结构标签,所以后续的是声明可能像下面这个样子:
Simple x;
Simple y[20],*z;
结构的自引用
在一个结构内部包含一个类型为该结构本身的成员是否合法化?例如:
<pre name="code" class="cpp">struct SELF_REF1{
int a;
struct SELF_REF1 b;
int c;
};
 
这种类型的自引用是非法的,因为成员b类型是另一个完整的结构体,其内部将包含它自身的成员b,这第2个成员有时另外一个完整的结构,它还将包含它自己的成员b,这样重复下去永无止境。这有点像永远不会终止的递归程序。但下面这个声明确实合法的:
<pre name="code" class="cpp">struct SELF_REF2 {
int a;
strcut SELF_REF2 *b;
int c;
};
 
这个声明和前面那个声明的区别在于b现在是一个指针而不是结构,编译器在结构的长度确定之前就已经知道指针的长度,所以这种类型的自引用是合法的。
如果你觉得一个结构内部包含一个指向该结构本身的指针有些奇怪,请记住它事实上所指向的是用一种类型的不同结构。
<pre name="code" class="cpp">警告:
警惕下面这个陷阱:
typedef struct {
int a;
SELF_REF3 *b;
int c;
}  SELF_REF3;
 
这个声明的目的是为了这个结构创建类型名SELF_REF3,但是它失败了,类型名直到声明的末尾才定义,所以在结构声明的内部它尚未定义。</span>
<pre name="code" class="cpp">解决办法是定义一个结构标签声明b,如下所示:
typedef struct SELF_REF3_TAG {
int a;
struct SELF_REF#_TAG *b;
int c;
} SELF_REF3;
 
->操作符的优先级高于&操作符的优先级。
作为函数参数的结构
结构变量是一个标量,它可以用于其他标量可以使用的任何场合。因此,把结构作为参数传递给一个函数是合法的,但这种做法往往并不适宜。
下面的代码取自一个程序,该程序用于操作电子现金收入记录。下面是一个结构的声明:
<pre name="code" class="cpp">typedef struct {
char product[PRODUCT_SIZE];
int quantity;
float uint_price;
float total_amount;
} Transaction;
 
当交易发生时,需要涉及很多步骤,其中之一就是打印收据。然我们看看怎样用集中不同的方法来完成这项任务。
<pre name="code" class="cpp">void print_receipt(Transaction trans)
{
printf(" %s\n",trans.product);
printf("%d @ %.2f total %.2f\n",trans.quantity, trans.uint_price,trans.total_amount);
}
 
如果current_trans是一个Transaction结构,我们可以像下面这样调用函数:
print_receipt(current_trans);
警告:
这个方法能够产生正确的结果,但它的效率很低,因为C语言的参数传递调用方法要求把参数的一份拷贝传递给函数,如果PRODUCT_SIZE为20,而且在我们使用的机器上整形和浮点都占4个字节,那么这个结构将占据32个字节的空间,要想把它作为参数进行传递,我们必须把32个字节复制到堆栈中,以后再丢弃。</span>
<pre name="code" class="cpp">把前面那个函数和下面这个进行比较;
void print_receipt(Transaction *trans)
{
<span style="white-space:pre">	</span>printf(" %s\n",trans->product);
<span style="white-space:pre">	</span>printf("%d @ %.2f total %.2f\n",trans->quantity, trans->uint_price,trans->total_amount);
}
 
这个函数可以想下面这样进行调用:
print_receipt(&current_trans);
这次传递给函数的是一个指向结构的指针,指针比整个结构要小得多,所以把它们压到堆栈上效果能提升很多。传递指针另外需要付出的代价是我们必须在函数中使用间接访问结构的成员。结构越大,把指向它的指针传递给函数的效率就越高。
想函数传递指针的缺点在于函数现在可以对调用程序的结构变量进行修改。如果我们不希望如此,可以在函数中使用const关键字来防止这类参数被修改。
位段
位段的声明和结构类似,但它的成员是一个或多个位的字段。这些不同的字段实际上存储于一个或多个整形变量中。
位段的声明和任何普通的结构成员声明相同,但有两个例外,首先,位段成员必须声明为int ,signed int ,unsigned int 类型,其次,在成员名的后面是一个冒号和一个整数,这个整数指定该位段所占位的数目。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值