[March , 20, 2008] Watcom C 的笔记11 Watcom C (11)

Watcom C 的笔记11 Watcom C (11)

				结构体对齐

    我是不主张使用汇编语言学习算法的,最主要的原因是汇编语言并不适合

构造复杂的数据结构。当然,在内存特别紧张的情况下,必须使用汇编语言做算法,

将会是非常痛苦的事情。我曾经研究过一段压缩代码,从上面的部分特征来看,

似乎是先用C语言实现算法,再尝试逐步转化为汇编语言的。额外的话题:BIOS

中的代码大部分是压缩后再存放的。AMI的压缩比大约高出Award 20-30%(个人

估计:)

    下面是我写程序中使用的结构体,编写中需要确定结构体中每个成员是否处在内存

中正确的位置,诸如freg0要在 50h 偏移处......

    struct spistruct{  			
      		uint32_t bfpr;	//00-03 BIOS Flash Primary Region
      		uint16_t hsfsts;//04-05 Hardware Squuencing Flash Status
      		uint16_t hsfctl;//06-07 Hardware Sequencing Flash Control
      		uint32_t faddr; //08-0B Flash Address
      		uint32_t rsrvd1;//0C-0F Reserved    		      		
      		uint8_t  fdata[0x40];//10-13 Flash Data 0
      				     //14-4F Flash Data N
      		uint32_t fracc; //50-57 Flash Region Access Permissions     		
      		uint32_t freg0; //54-57 Flash Region0
      		uint32_t freg1; //58-5B Flash Region1     		      		
      		uint32_t freg2; //5C-5F Flash Region2
      		uint32_t freg3; //60-63 Flash Region3     		      		      		
      		uint32_t freg4; //64-67 Flash Region4      		
      		uint8_t  rsrvd2[12];//68-73 Reserved    		      		      		
      		uint32_t fpr0;  //74-77 Flash Protected Range 0
      		uint32_t fpr1;	//78-7B Flash Protected Range 1
      		uint32_t fpr2;  //7C-7F Flash Protected Range 2
      		uint32_t fpr3;  //80-83 Flash Protected Range 3
      		uint32_t fpr4;  //84-87 Flash Protected Range 4
      		uint32_t rsrvd3[2];//88-8F Reserved
      		uint8_t  ssfsts;//90    Software Squency Flash Status
      		uint16_t ssfctl1;//91-92        		      		      		
      		uint8_t  ssfctl2;//93	 //91-93 Software Squency Flash Control
      		uint16_t preop;	//94-95 Prefix Opcode Configuration
      		uint16_t optype;//96-97 Opcode Type Configuration
      		uint8_t opmenu[8];//98-9F Opcode Menu Configuration      		
      		uint32_t bbar;	//A0-A3    BIOS Base Address Configuration
       		uint32_t rsrvd4[3];//A4-AF Reserved
      		uint32_t fdoc;	//B0-B3 Flash Descriptor Observerability Control
      		uint32_t fdod;	//B4-B7 Flash Descriptor Observerability Data      		
       		uint32_t rsrvd5[2];//B8-BF Reserved4
       		uint32_t afc;		//C0-C3 Additional Flash Control Register     
       		uint32_t lvscc; //C4-C7 Host Lower Vendor Specific Component Capabilities Register      		 		
       		uint32_t uvscc; //C8-CB Host Upper Vendor Specific Component Capabilities Register
       		uint32_t rsrvd6;//CC-CF Reserved
       		uint32_t fpb;		//D0-D3     		
} ;

    最初,我采用的是笨办法:给成员赋值,然后查看是否出现在应该的内存位置。

后来发现了一个很好用的宏,它是标准库的扩充,可以直接使用:

	#define offsetof(type,memb) ((size_t) & ((type *) 0)->memb 参考[2]

    使用的例子: printf("[%lx]  [%x]\n",spi->opmenu[0],offsetof(struct spistruct,opmenu) );

    随后调试中又发现 ssfctl1 成员总是不能处在正确的位置上。经过研究发现,

结构体中有一个"对齐"的问题。因为内存如果对齐的话,会节省访问时间。我们希望

成员处于91h的位置,而由于对齐,编译器会将其放在92h处对齐。

    Watcom C 中上述问题可以用下面的方法解决:

#pragma pack(1)		//指定按照 1 byte 对齐
struct spistruct{  			
      		uint32_t bfpr;	//00-03 BIOS Flash Primary Region
      		uint16_t hsfsts;//0
          ... ... ... ...
          ... ... ... ...
          ... ... ... ...

参考:

[1] 败中求胜——Qdieyou个人工作室
http://blog.csdn.net/Qdieyou/archive/2007/04/26/1585715.aspx

[2]《C语言参考手册》 P325

						Zoologist
						2008-3-20

[March , 17, 2008] DOS下的C语言编辑器 我之前之前一直使用Boxer,感觉很糟糕。这个编辑器似乎是专门为Watcom C 设计的,不过最好不要配置在IDE中编译,我试验发现编译经常会死机。也许以后有时间我会考虑写一个类似Turbo C的编辑器吧。

DOS下的C语言编辑器 我之前之前一直使用Boxer,感觉很糟糕。这个编辑器似乎是专门为Watcom C 设计的,不过最好不要配置在IDE中编译,我试验发现编译经常会死机。也许以后有时间我会考虑写一个类似Turbo C的编辑器吧。

wc

[March , 15, 2008] Watcom C 的笔记10 Watcom C (10)

Watcom C 的笔记10 Watcom C (10)

		局部变量在内存的位置

    在编写一个com文件的时候,遇到奇怪的问题:编译正常,运行后显示

“Stack Overflow!”。程序片段如下:

#include <stdio.h>

int main(int argc,char *argv[])
{
 int i,n;
 FILE *f;
 long int sum=0;
 char buffer[2048]=; //1K 就在这里指定一个做buffer的变量

 if (argc!=2) {printf("usage: checksum file

     试验表明,如果在1024之上就会出现这个错误。在编译过程中,还发现

这个地方的大小不会影响生成com文件的大小。查阅资料【参考1】,上面说

局部变量存放在堆栈中... ...因此如果太大了自然会出现堆栈溢出的问题。

    设置为全局变量就可以了,这样并不会影响生成文件的大小,看起来仍然是

在运行过程中动态分配的。分配在代码和堆栈之间的空间。具体如何确定,还不

清楚。

    编译批处理文件 mkchk.bat
     wcc checksum /ms 
     wlink system com file checksum
    源程序:
#include <stdlib.h>
#include <stdio.h>

char buffer[0xC000]; //48K

int main(int argc,char *argv[])
{
 int i,n;
 FILE *f;
 unsigned long int sum=0;

 if (argc!=2) {printf("usage: checksum filename\n"); exit(1);};

 //argv[0] is executable file name
 f=fopen(argv[1],"r+b");
 if (f==NULL) {printf("File open error!");}

 n=fread(buffer,sizeof(char),sizeof(buffer),f);
 while (n!=0)
   {
   	for (i=0;i<n;i++)
   	  {
   	  	sum=sum+buffer[i];
   	  }
 n=fread(buffer,sizeof(char),sizeof(buffer),f);   	  
   }

 printf("Checksum in BYTE:  %12hX\n",sum & 0xFF);
 printf("Checksum in WORD:  %12X\n", sum & 0xFFFF);
 printf("Checksum in DWORD: %12lX\n",sum);  
 return 0;
}

    运行结果:

G:\watcomc>checksum dos4gw.exe
Checksum in BYTE:            40
Checksum in WORD:          3E40
Checksum in DWORD:     F0153E40    

参考:

1.http://topic.csdn.net/t/20040316/12/2848204.html

				2008-3-15
				Zoologist

[March , 10, 2008]风俗问题

            		风俗问题

    有一段时间,我认为只有有钱人家风俗多,规矩多,后来发现根本不是

那么回事。比如,我在家吃饭的时候,俺爹总是教育我吃米饭不要趴着吃,

要端起碗吃。又说,这要是在老家你奶奶肯定一筷子打过来。等到我上学了,

工作了,用不锈钢盘子吃饭觉得很别扭,总想端起来吃,而端起来之后又过于

与众不同,大多数人都会认为你要舔盘子。另外,在老家,吃咸鸭蛋的时候,

也有要求必须从什么大头打开,而我总是敲到实心的那一端。

    现在我家保留着最有特点的风俗就是烧纸。通常是在过年前几天,买好

黄纸。在另外一张纸上,如同信封一般,写好“收件人”,不过都是“匿名信”,

决不能落款否则不吉利。给不同人的要分开写,分开烧。也从来没见过“XXX

同志转XXX同志收”,想必下面的世界邮政事业很发达。

    一般都在十字路口烧,莫非是因为交通方便?烧之前,先要检几个树枝

在地上画一个圈,在圈中烧。点燃之后,用树枝翻动,这样才能烧得干净。

在烧的过程中,还要再点燃几张放在圈外,意思是给路过的“大鬼”“小鬼”。

一边烧,还要一边念去世亲属的名称,说来收钱吧。

    我第一次正式执行这个风俗大约是在大二的寒假,在这之前通常只有回老家

才会烧纸。下楼,画圈,烧纸。然后按照妈妈教导念道“爷爷、姥爷来收纸吧”。

俺娘笑,我急忙改口说来收钱吧。心里想着大家都烧,多影响人家的金融秩序啊,

不知道会不会通货膨胀啊?

    今年回去也烧了。和父亲一起去的。路口有清洁工一直守候在那。看见

我们来,直接递给我们两个树枝。随后聊了几句得知,他们每天都会守在这里,

直到夜里12点,负责打扫灰烬。前几天还有城管带着大铁槽,要求人们直接在

里面烧。地上是大片烧过留下的黑色。

    妈妈说,很多很多年以前,烧纸是作为封建迷信活动严加禁止的。只是

后来又慢慢开始了。按道理说我是一个无神论者,不过俺娘说,这是风俗,

让你不要忘记先人。并且,我还是很喜欢烧东西这样事情的。

    以前有一个笑话是说,中国人摆上水果供在墓碑前,洋人是摆放着鲜花的。

洋人就问道:你们的先人什么时候出来吃这些东西啊?中国人回答,当你们的

先人出来闻鲜花的时候,我们的先人就出来吃东西了。

							Zoologist
							2008-3-10

[March , 7, 2008] Watcom C 的笔记9 Watcom C (9)

Watcom C 的笔记9 Watcom C (9)

          运算优先级的问题

    C语言中,“+ -”的优先级高于“<< >>”因此,下面这段程序无法得到期望值:

#include <stdio.h>
#include <stdint.h>
void main ()
{
	uint8_t		command_write=1;
	uint8_t		command_read=2;
	uint8_t		command_erase=3;
	uint8_t		command_read_status=4;

	uint64_t rst=0xFFFFFFFF;

	rst =       command_write+
			command_read<<8+
			command_erase<<16+
			command_read_status<<24;

	printf("[%08lX]\n",rst);
}	

     最简单的方法是将表达式改为下面的形式:

	rst =       command_write+
			(command_read<<8)+
			(command_erase<<16)+
			(command_read_status<<24);

					9:23 2008-1-21

[March , 3, 2008] Watcom C 的笔记8 Watcom C (8)

           随机函数

    stdlib.h 中的 int rand(void) 产生随机数。需要注意的是,生成的

范围是 0-32767。 直接使用这个参数生成的是伪随机数。

#include <stdio.h>
#include <stdlib.h>
int main()
{
 int i;

  for (i=0;i<0x200;i++)
   {
   	if ((i % 0x10)==0) {printf("\n");}
    printf("%5d ",rand());
   }
 return 0;
}

    上面这个程序将生成256个随机数,因为产生的是伪随机数,因此,两次

运行产生的结果是相同的。

    使用 void srand( unsigned int seed ) 会指定随即种子,但是对于

相同的随机种子,产生的序列还是一样的 ... ... 看来生成随机数真的有必要

使用时钟生成种子。

    clock_t clock(void) 是同 rdstc 类似的函数,

#include <stdio.h>
#include <math.h>
#include <time.h>
#include <limits.h>
void compute( void )
{
int i, j;
double x;
x = 0.0;
for( i = 1; i <= 10000; i++ )
for( j = 1; j <= 10000; j++ )
x= sqrt( (double) i * j );
printf( "%16.7f\n", x );
}
void main()
{
  clock_t starttime,endtime;
	starttime=clock(); //开始计时
	compute();
	endtime=clock();   //停止计时
	printf( "Execution time was %lu \n",(endtime-starttime)/CLOCKS_PER_SEC); //显示经过了多少秒
 }

     使用time函数获取当前时间,结果是32位的unsigned long,想必可以

用来做随机种子。

#include <stdio.h>
#include <time.h>
void main()
{
  time_t time_of_day;
  time_of_day = time (NULL);
	printf( "%lu \n",time_of_day);
 }

						Z.t
						2008-1-22

[February , 27, 2008] 回乡偶记

		     回乡偶记

(一)回来之后,听亲戚讲述我奶奶家的历史,让我颇感惊讶。第一件事情是,

我爷爷是48年县城的第一批秘密党员。那时候还没有解放,秘密入的;第二件

事情是,我奶奶家是地主。汗,我一直以为我是“根正苗红”的“三代贫农”

----不过要从我爷爷出身算,是。

(二)飞回来上班的。印象深刻的是坐火车次次都有人广播找医生;坐飞机似乎

次次都有带小孩子的,哭声不断。

(三)飞机上打起来了。一个男人,带着一个女的,女的怀抱很小的孩子,还有

个大约11岁的男孩,不知道什么关系。飞机上的空间挺小的,前面的一个人将

座椅放下来了,大约是阻挡了他的活动吧,双方发生了争执。只见这个人,

向前一探,一把将前排那个乘客的衬衣撕开了。声音很响,刹那间“锦帛相见”

这个词语竟然跳入脑中... ...稍后,飞机上的工作人员过来了,请后面的这个

人到后舱。随后,传出那个男人的声音。他说,这要是在地上,早把他的脑袋

拧下来了... ...又说,我们东北人就是这样,这也不是什么歧视的问题... ...

听了然人觉得好笑。这么大的脾气至少是个“处长”什么的吧。随后,抱着孩子的

女子,急忙掏出200块,求前面的男的私了。再后来,飞机准备降落了,机上工作

人员拿了4个装呕吐物的袋子(没用过的),让旁边的乘客帮着写下事情的经过。

衬衣被撕坏的乘客始终坚持必须道歉,而施暴者坚持不肯。另外也只肯出200块。

再后来,飞机降落了,其余的乘客鱼贯而出,飞机上的这5个人准备到地面解决问题。

坐我前面的女乘客走到“受害者”面前说,最看不惯你这种人,欺负孤儿寡母的,

还说衬衣500块,这不是讹人吗(一时间我都闹不清楚逻辑关系了)。那个人,

讪讪无语。东北女人豪爽,汗~

(四)飞机准备降落了,空中小姐敲厕所门,让里面的人抓紧出来... ...和火车差

不多啊~ 火车到站,就要关闭厕所,通常是乘务员狂敲一阵让里面的人出来。我也

多次见过乘客面目狰狞的恳求乘务员通融一下,行个方便。

(五)在家掰辣椒。晾干的红辣椒准备做辣椒油吃。我用手揉碎之。摸了一下鼻子,

立马火烧火燎。求助于老娘,老娘说,你要用剪子,或者套上塑料带,直接用手会很辣,

严重的话手指都会觉得辣。哎,你真没有生活常识啊。辣了吧,用醋试试。我急忙找了

个棉签,沾上醋,擦之。无效,还仿佛扩散了。黄豆大的汗珠不断落下。忽然问,

这个好用吗?老娘曰,不知道,不过你看凉菜咸了或者辣了都是加醋啊!后面我又偷着

试验了油性的化妆品,也不好用。最后打了一盆凉水,扎在里面了......

    晚上,睡觉的时候舔了一下手指,还是很辣的,不敢乱摸了。

					Zoologist
					2008-2-27

[February , 22, 2008] Watcom C 的笔记7 Watcom C (7)

Watcom C 的笔记7 Watcom C (7)

		        判断是否在 Windows 下

    之前使用int 2Fh,ax=1600h 的方法已经失效;现在提出检测CR0 的Bit0 

(V86 enabled位)。在Windows的DOS box是 v86 mode。

#include <stdio.h>
#include <i86.h>

extern short isV86( void );
#pragma aux isV86 =       \
    "smsw  ax           ",      \
    "test  ax, 1        ",      \
    "jz    V86       ",      \
    "xor   ax, ax       ",      \
    "V86:            ",      \
    "mov   ax, 1        "       \
value [ ax ];

void main()
{
		if (isV86() ==0) 
					{printf("The program is running in pure DOS\n");}
		else 
					{printf("The program is running in Windows!\n");}	
}			

    实验表明,DOS下,上面的程序不好用,仍然会判断为在Windows下,因为DOS4GW

实现的也是要使得程序进入保护模式。

Function 0400H This function returns the version of DPMI services supported. Note that this
is not necessarily the version of any operating system that supports DPMI. It
should be used by programs to determine what calls are legal in the current
environment. Pass the following information:
AX = 0400H
The information returned is:
AH = Major version
AL = Minor version
BX = Flags Bit 0 = 1 if running under an 80386 DPMI implementation. Bit 1
= 1 if processor is returned to real mode for reflected interrupts (as
opposed to Virtual 8086 mode). Bit 2 = 1 if virtual memory is
supported. Bit 3 is reserved and undefined. All other bits are zero
and reserved for later use.
CL = Processor type
02 = 80286
03 = 80386
04 = 80486
05 = Pentium
DH = Current value of virtual master PIC base interrupt
DL = Current value of virtual slave PIC base interrupt
Carry flag clear (call cannot fail)

     返回值中的 BX Bit1 =1 表明返回到Real Mode下;Bit1 =0 表明返回的是V86模式下。

#include <stdio.h>
#include <i86.h>

void main()
{
		union	REGS r;

		r.w.ax=0x400;
		int386(0x31,&r,&r);

		if ((r.w.bx & 2)==0) 
					{printf("The program is in Windows!\n");}
		else 
					{{printf("The program is in DOS!\n");}}	
}			

     实验表明很好用~

						Z.t
						2008-1-20