2 试用结构体(harib02b)
上面的方法倒也不能说不好,只是代码的行数多了些,不太令人满意。而如果采用之前的COLUMN-2里(第4章)的写法:
xsize = *((short *) 0x0ff4);
程序长度是变短了,但这样的写法看起来就像是使用了什么特殊技巧。我们还是尝试一下更普通的写法吧。
本次的HariMain节选
struct BOOTINFO { char cyls, leds, vmode, reserve; short scrnx, scrny; char *vram; }; void HariMain(void) { char *vram; int xsize, ysize; struct BOOTINFO *binfo; init_palette(); binfo = (struct BOOTINFO *) 0x0ff0; xsize = (*binfo).scrnx; ysize = (*binfo).scrny; vram = (*binfo).vram;
我们写成了上面这种形式。struct是新语句。这里第一次出现结构体,或许有人不太理解,如果不明白的话请一定看看后面的专栏。
最开始的struct命令只是把一串变量声明集中起来,统一叫做“struct BOOTINFO”。最初是1字节的变量cyls,接着是1字节的变量leds,照此下去,最后是vram。这一串变量一共是12字节。有了这样的声明,以后“struct BOOTINFO”就可以作为一个新的变量类型,用于各种场合,可以像int、char那样的变量类型一样使用。
这里的*binfo就是这种类型的变量,为了表示其中的scrnx,使用了(*binfo).scrnx这种写法。如果不加括号直接写成*binfo.scrnx,虽然更容易懂,但编译器会误解成*(binfo.scrnx),出现错误。所以,括号虽然不太好看,但不能省略。
COLUMN-5 结构体的简单说明
5.2节里的这种结构体的使用方法,比较特殊。我们先看一个普通的例子。
普通的结构体使用方法
void HariMain(void) { struct BOOTINFO abc; abc.scrnx = 320; abc.scrny = 200; abc.vram = 0xa0000; (以下略) }
先定义一个新结构体变量abc,然后再给这个结构体变量的各个元素赋值。结构体的好处是,可以像下面这样将各种东西都一股脑儿地传递过来。
func(abc);
如果没有结构体,就只能将各个参数一个一个地传递过来了。
func(scrnx, scrny, vram, ...);
所以很多时候会将有某种意义的数据都归纳到一个结构体里,这样就方便多了。但如果归纳方法搞错了,反而带来更多麻烦。
为了让程序能一看就懂,要这样写结构体的内部变量:在结构体变量名的后面加一个点(.),然后再写内部变量名,这是规则。
■■■■■
下一步是使用指针。这是5.2节中的使用方法。声明方法如下:
变量类型名 *指针变量名;(回想一下char *p; )
而这次的变量类型是struct BOOTINFO,变量名是binfo,所以写成如下形式:
struct BOOTINFO *binfo;
这里的binfo表示指针变量。地址用4个字节来表示,所以binfo是4字节变量。
因为是指针变量,所以应该首先给指针赋值,否则就不知道要往哪里读写了。可以写成下面这样:
binfo = (struct BOOTINFO *)0x0ff0;
本来想写“binfo =0x0ff0; ”的,但由于总出警告,很讨厌,所以我们就进行了类型转换。
设定了指针地址以后,这12个字节的结构体用起来就没问题了。这样我们可以不再直接使用内存地址,而是使用*binfo来表示这个内存地址上12字节的结构体。这与“char *p; ”中的*p表示p地址的1字节是同样道理。
前面说过,想要表示结构体abc中的scrnx时,就用abc.scrnx。与此类似,这里用(*binfo).scrnx来表示。需要括号的理由在5.2节中已经写了。因此语句写作:
xsize = (*binfo).scrnx;