[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

[February , 18, 2008] Watcom C 的笔记6 Watcom C (6)

Watcom C 的笔记6 Watcom C (6)

          命令行参数的获得

    标准C语言定义如下: int main(int argc,char *argv[])。

第一个字符串 argv[0] 是包含全路径的程序名。

#include <stdio.h>
int main(int argc,char *argv[])
{
 int i;
 printf("You have input %d arguments. Argv[0]=[%s]\n",argc-1,argv[0]);
 //argv[0] is file name
 for (i=1;i<argc;i++)
   {
    printf("argument %d:[%s]\n",i,argv[i]);
   }
 return 0;
}

G:\>getarg /L p oo.bak
DOS/4GW Protected Mode Run-time  Version 1.97
Copyright (c) Rational Systems, Inc. 1990-1994
You have input 3 arguments. Argv[0]=[G:\GETARG.EXE]
argument 1:[/L]
argument 2:[p]
argument 3:[oo.bak]

    修改一下,枚举文件和目录的例子:

#include <stdio.h>
#include <dos.h>
int main(int argc,char *argv[])
{
	struct find_t fileinfo;
	unsigned	rc;
	/* Display name and size of "*.c" files */
	rc=_dos_findfirst("*.*",_A_NORMAL+_A_RDONLY+_A_HIDDEN+_A_SYSTEM+_A_SUBDIR,&fileinfo);
	while ( rc == 0)
	  {
	  	//take care of this: the priority of "==" is higher than "&"
	  	if ((fileinfo.attrib & _A_SUBDIR)==0) 
	  					{printf("%14s %10ld\n",fileinfo.name,fileinfo.size);} //File
	  	else 	
	  					{printf("%14s      <DIR>\n",fileinfo.name);}					//Directory
	  	rc= _dos_findnext(&fileinfo);
	  }	

 return 0;
}

运行结果:

       RDTSC.C        429
           PCI      <DIR>
      PRACTICE      <DIR>
   GETCHAR.EXE      33236
      COMP.BAT        107
   GETCHAR.OBJ        483
       PTEST.C        667
       HELLO.C         86
          NOTE      <DIR>
     PTEST.OBJ        551
     PTEST.EXE      33256
      GETARG.C        257
     EMUFILE.C        596
      MAIN.EXE      33372
      MAIN.OBJ        504
         R.TXT       1543
    GETARG.OBJ        526
     HELLO.OBJ        409
   EMUFILE.EXE      33384
   EMUFILE.OBJ        574
     HELLO.EXE      33216
   MEMTEST.OBJ        464
     HELLO.ERR         54

						Z.t
						2008-1-19

[January , 26, 2008] Watcom C 的笔记5 Watcom C (5)

Watcom C 的笔记5 Watcom C (5)

          DOS/4GW PCI 配置空间的读取

   参考

http://www.openwatcom.org/index.php/PCI_Device_access_under_32-Bit_PM_DOS

很奇怪的是原文是编译不过的,需要将 Example 中的 #include "pci.h" 改为 

#include "pci.c" 才能编译通过。

   第一个程序:getpci.c 使用二维数组保存结果,在后面输出:

#include <stdio.h>
#include "pci.c"
int main()
{
char pcicon[0x10][0x10];
uint8_t bus, dev, func;
short int i,j;
   printf("Please input BUS DEV FUN");
   scanf("%hx %hx %hx",&bus,&dev,&func);
   for (i=0;i<0x10;i++)
     for (j=0;j<0x10;j++)
       {
	 pcicon[j][i]=PciReadConfigByte(bus,dev,func,(char) (j+i*16));
	}

   for (i=0;i<0x10;i++)
     {
     printf("\n");
     for (j=0;j<0x10;j++)
       {
	printf("%02x ",pcicon[j][i]);
	}
     }
 return( 0 );
}

   第二个程序:getpci1.c 动态分配内存,使用指针保存分配的内存首地址。

#include <stdio.h>
#include <stdlib.h>
#include "pci.c"
int main()
{
char *pcicon; //指针
uint8_t bus, dev, func;
short int i,j;
   printf("Please input BUS DEV FUN");
   scanf("%hx %hx %hx",&bus,&dev,&func);
   pcicon=malloc(0x100);
   if (pcicon==NULL) {printf("Error");}
   for (i=0;i<0x10;i++)
     for (j=0;j<0x10;j++)
       {
	 *(pcicon+i*16+j)=PciReadConfigByte(bus,dev,func,(short int) (j+i*16));
	}

   for (i=0;i<0x10;i++)
     {
     printf("\n");
     for (j=0;j<0x10;j++)
       {
	printf("%02X ",*(pcicon+i*16+j));
	}
     }
  free(pcicon);
 return( 0 );
}

   第二个程序:getpci2.c 动态分配内存,使用数组指针。

#include <stdio.h>
#include <stdlib.h>
#include "pci.c"
int main()
{
char (*pcicon)[0x10][0x10]; //数组指针(指向数组的指针)
uint8_t bus, dev, func;
short int i,j;
   printf("Please input BUS DEV FUN");
   scanf("%hx %hx %hx",&bus,&dev,&func);
   pcicon=malloc(0x200);
   if (pcicon==NULL) {printf("Error");}
   for (i=0;i<0x10;i++)
     for (j=0;j<0x10;j++)
       {
	 (*pcicon)[i][j]=PciReadConfigByte(bus,dev,func,(short int) (j+i*16));
	}

   for (i=0;i<0x10;i++)
     {
     printf("\n");
     for (j=0;j<0x10;j++)
       {
	printf("%02X ",(*pcicon)[i][j]);
	}
     }
  free(pcicon);
 return( 0 );
}

    编译后的程序都是无法在XP下面运行的(运行结果不确定),只能在DOS下运行。

另外,参考的访问PCI配置空间的方法是调用PCI BIOS中断。

						Z.t
						2008-1-17