c语言中断处理
系统级C语言程序设计(中断原理简介)   
  摘要:本文主要介绍C语言中中断服务程序的编写、安装和使用。由于硬中断服务程序的编写涉及到硬件端口读写操作,使得用户直接和硬件打交道,在程序设计过程中要用到的数据(如硬件端口地址等)比较多,这就使程序员和计算机的硬件设备间缺少一种“缓冲”的作用,况且,用汇编语言来直接对硬件编程要方便得多。 本文仅对软中断程序的编写作个介绍。 
  关键词:软中断、中断向量、中断向量表、TSR内存驻留、DOS重入、中断请求、段地址、偏移量、寄存器、BIOS、DOS、setvect()、getvect()、keep ()、disable()、enable ()、geninterrupt ()、int86 ()、interrupt 
  对于一般的C语言爱好者而言,就如何在C中使用中断例程这一问题应该已经非常熟悉,例如,我们可以通过int86  (  )函数调用13H号中断直接对磁盘物理扇区进行操作,也可以通过INT86  (  )函数调用33H号中断在屏幕上显示鼠标光标等。其实,13H号也好,33H号也好,它们只不过就是一些函数,这些函数的参数通过CPU的寄存器传递。中 断号也只不过是间接地
指向函数体的起始内存单元,说它是间接的,也就是说,函数的起始段地址和偏移量是由中断号通过一种方法算得的(具体如何操作,下面会 作解释)。如此一来,程序员不必要用太多的时间去写操作硬件的程序了,只要在自己的程序中设置好参数,再调用BIOS或DOS提供的中断服务程序就可以 了,大大减小了程序开发难度,缩短了程序开发周期。那么中断既然是函数,就可以由用户任意的调用、由用户任意地编写。 
   计算机内存的前1024个字节(偏移量00000H到003FFH)保存着256个中断向量,每个中断向量占4个字节,前两个字节保存着中断服务程序的入 口地址偏移量,后两个字节保存着中断程序的入口段地址,使用时,只要将它们分别调入寄存器IP及CS中,就可以转入中断服务程序实现中断调用。每当中断发 生时,CPU将中断号乘以4,在中断向量表中得到该中断向量地址,进而获得IP及CS值,从而转到中断服务程序的入口地址,调用中断。这就是中断服务程序 通过中断号调用的基本过程。在计算机启动的时候,BIOS将基本的中断填入中断向量表,当DOS得到系统控制权后,它又要将一些中断向量填入表中,还要修 改一部分BIOS的中断向量。有一部分中断向量是系统为用户保留的,如60H到67H号中断,用户可以将自己的中断服务程序写入这些中断向量中。不仅如 此,用户还可以自己更改和完善系统已有的中断向量。 
  在C语言中,提供了一种新的函数类型interrupt,专门用来定义中断服务程序,比如我们可以写如下的中断服务程序: 
  /*例1:中断服务程序*/ 
  void  interrupt  int60() 
  { 
  puts("This  is  an  example"); 
  } 
  该中断的功能就是显示一个字符串,为什么不用printf  (  )函数呢?这就牵涉到DOS的重入问题,后面将作一些介绍。 
          一个简单的中断服务程序写好了,如何把它的函数入口地址填写到中断向量表中,以便在产生中断的时候能转入中断服务程序去执行呢?这里要用到setvect  (  )和getvect  (  )函数。setvect  (  )有两个参数:中断号和函数的入口地址,其功能是将指定的函数安装到指定
的中断向量中,getvect  (  )函数有一个参数:中断号,返回值是该中断的入口地址。在安装中断以前,最好用disable  (  )函数关闭中断,以防止在安装过程中又产生新的中断而导致程序运行混乱,待安装完成后,再用enable  (  )函数开放中断,使程序正常运行。现在我们可以把上面的例子再丰富一下: 
  /*例2:中断服务程序的编写、安装和使用*/   
  #include  <dos.h>     
  #include  <stdio.h>     
  #ifdef  __cplusplus     
  #define  __ARGU  ...     
  #else 
   
  #define  __ARGU     
  #endif     
  void  interrupt  int60  (__ARGU)    /*中断服务函数*/     
  { 
    puts("This  is  an  example"); 
    }     
  void  install  (void  interrupt  (*fadd)(__ARGU),int  num)  /*安装中断*/ 
  { 
  disable();  /*关闭中断*/ 
  setvect(num,  fadd);  /*设置中断*/ 
  enable();  /*开放中断*/ 
  } 
  void  main() 
  { 
  install  (int60,0x60);/*将int60函数安装到0x60中断*/ 
  geninterrupt  (0x60);  /*人为产生0x60号中断*/ 
  } 
  有一定经验的读者很容易得到该程序的执行结果:在屏幕上显示“This  is  an  example!”。 
          编写、安装中断服务程序的方法就介绍这些。下面再浅谈一下内存驻留程序(TSR)的编写和使用。在C语言中,可以用keep  (  )函数将程序驻留内存。这个函数有两个参数:status和size。size为驻留内存长度,可以用size=_SS+_SP/16-_psp得到,当 然这也是一种估算的方法,并不是精确值。函数执行完以后,出口状态信息保存在status中。比如,对于上面的例子,将“geninterrupt  (0x60);”改写成“keep(0,_SS+_SP/16-_psp);”后再执行程序,这一段程序就被驻留,此后在其它的任何软件或程序设计中,只 要用到了60H号中断,就会
在屏幕上显示“This  is  an  example!”的字样。要恢复系统对60H号中断的定义,只能重新启动计算机。 
          像上面的例子其实还很不完善,它没有考虑DOS系统环境的状态、没有考虑程序是否已经驻留内存、没有考虑退出内存驻留等问题。对于第二个问题还是很容易解 决的:执行程序一开始就读取某一函数中断入口地址(如63H号中断)判断是否为空(NULL),如果为空就先将该地址置为非空再驻留内存,若为非空则表示 已经驻留并退出程序。这一步判断非常重要,否则将会因为重复驻留占用过多内存空间而最后造成系统崩溃。至于其它两个问题,在此不多作说明,有兴趣的读者可 以参考一些有关书籍。 
          不仅如此,我们还可以通过在DOS下使用热键(Hotkey)来调用内存驻留程序。比如将《希望汉字系统》自带的《希望词典》驻留内存后,在任意时刻按下 Ctrl+F11键,就能激活程序,出现词典界面。微机的键盘中有一个微处理芯片,用来扫描和检测每个按键的按下和释放状态。大多数按键都有一个扫描码, 告知CPU当前的状态,但一些特殊的键如PrintScreen、Ctrl+Break等不会产生扫描码,而直接产生中断。正因为如此,我们可以将 Ctrl+Break产生的中断号指向我们自己写好的程序入口地址,那么当按下Ctrl+Break后,系
统就会调用我们自己的程序去执行,这实际上也就 是修改了Ctrl+Break的中断向量。至于其它按键激活程序则可以利用9H号键盘中断捕获的扫描码来实现,在此不多作说明。例如,执行下面的程序后, 退回DOS系统,在任意的时候按下Ctrl+Break后,屏幕的底就会变成红。 
  /*例3:中断服务程序编写、安装和使用,内存驻留*/ 
  #include  <dos.h> 
  #include  <conio.h> 
  #ifdef  __cplusplus 
  #define  __ARGU  ... 
  #else 
  #define  __ARGU 
  #endif 
  void  interrupt  newint(__ARGU);  /*函数声明*/ 
  void  install  (void  interrupt  (*fadd)(__ARGU),  int  num); 
  int  main() 
  { 
  install  (newint,0x1b);  /*Ctrl+Break中断号:1BH*/ 
  keep(0,_SS+(_SP/16)-_psp);  /*驻留程序*/ 
  return  0; 
  } 
  void  interrupt  newint(__ARGU) 
  { 
  textbackground(4);  /*设置屏幕底为红*/ 
  clrscr();  /*清除屏幕*/ 
  } 
c语言printf用法例子简单
  void  install  (void  interrupt  (*fadd)(__ARGU),  int  num) 
  { 
  disable(); 
  setvect(num,fadd);  /*设置中断*/ 
  enable(); 
  } 
          由于13H号中断是BIOS提供的磁盘中断服务程序,对于DOS下的应用程序,它们的存盘、读盘功能都是通过调用这一中断来实现的。有许多DOS下的病毒就喜欢修改13H号中断来破坏系统,例如,修改13H号中断服务程序,将其改成: 
  /*例4:病毒体程序伪代码*/ 
  void  interrupt  new13(__ARGU)   
  { 
  if  (病毒发作条件成熟) 
  {  修改入口参数指向病毒程序入口地址; 
      执行病毒代码; 
  } 
  调用原来的13H中断; 
  } 
  只要当任一软件(如EDIT.COM等)对磁盘有操作并且病毒发作条件成熟时,病毒就被激活。当然,这样做会导致可用内存空
Linux中断编程
在  Linux  下,硬件中断被称为  IRQs  [Interrupt  Requests  (这是Linux起源的Intel  架构上的标准术语。  )的缩写]。有两种  IRQs,短的和长的。一个短的  IRQ  预期占用  非常短的一段时间,在那期间,机器的剩余部分被阻塞,没有其他的中断将被处理。长的  IRQ  占用的时间长些,在那期间其他中断有可能发生(但不能是来自同一设备)。只要是可能的,声明一个长中断是较好的。