11.9 Declaring parameters for register call functions

  ------------------------------------------------------

 

      There used to be a specific register corresponding strictly to each

  parameter of a register function. For instance, for variables of type 'int'

  or 'word' the first parameters was transferred via AX, the second via BX,

  the third via CX, the fourth via DX, the fifth via DI, and the sixth via

  SI. Therefore in order to transfer only one parameter via SI, you first had

  to write five commas before it. The following example is a call to the

  function 'STRCPY':

 

  void main ()

  {

    STRCPY ( , , , , #dest, #sourc ) ;

  }

 

      Now, however, registers can be used in any way when transferring

  parameters. You only need to tell the compiler which register is assigned

  to each parameter of a function. After this declaration, the compiler will

  take care of which register a function parameter is transferred to, its

  size, and the number of parameters being transferred.  Here is an example

  of the declaration and use of 'STRCPY':

 

  void STRCPY ( DI, SI );     // function declaration

 

  void main ()

  {

    STRCPY ( #dest, #sourc ); // function call

  }

 

      Instead of declaring a function, you can indicate the position of the

  registers in the function heading. But then the function can be called only

  after it has been defined. Here is an example of a function which displays

  several identical characters:

 

  void PUTNCHAR(AL,CX,BL,BH)

  /* 1 parameter to AL - code for character to be displayed

     2 parameter to CX - number of characters to be displayed

     3 parameter to BL - color attribute

     4 parameter to BH - video mode

  */

  {

    AH=9;

    $INT 0x10

  }

 

      When declaring a register function, you can also indicate the type of

  variable expected by the function (signed, unsigned, or float). The default

  is signed. But it only makes sense to indicate signed if the parameter is

  transferred via registers AL, AX, or EAX. The variable is always

  transferred via other registers as unsigned. Here is an example of

  declaring a register function with indication of type:

 

  int fastcall Exampl(word CX, int AX, DX, float ESI ) ;

   |    |        |        |         |   |   |

   |    |        |        |         |   |   |---- 4 param. has a type float

   |    |        |        |         |   |         and re-d. over register ESI.

   |    |        |        |         |   |-------- 3 param. has on default type

   |    |        |        |         |             word and re-d. over DX.

   |    |        |        |         |------------ 2 param. has a type int and

   |    |        |        |                       is transferred over register AX.

   |    |        |        |---------------------- 1 param. has a type word and

   |    |        |                                is transferred over register CX.

   |    |        |------------------------------- Name declared function.

   |    |---------------------------------------- Modifier, pointing that

   |                                              this funct. register.

   |--------------------------------------------- Function returns change.

                                      type int.

 

      If the function registers were declared, the compiler will keep strict

  track of the number of these parameters when calling the function and will

  give error messages if there are too few or too many. On one hand this is

  good - if it tracks them, nothing will be forgotten and and nothing extra

  will be added when calling a function. On the other hand, there are

  sometimes unnecessary parameters and these will need to be registered. But

  if you neglect to register one parameter when calling a function, the

  compiler will give an error message. This makes it possible to initialize

  the register via which the parameters are being transferred apart from

  calling the function. If one paremeter is registered, however, all the

  others will need to be registered or else the compiler will think it was

  accidentally omitted and will give an error message.

 

      If registers were not declared either during declaration of a register

  function or in the heading of the function itself, the compiler will think

  that the parameters are to be transferred to this function by the old

  method. This makes for perfect compatibility with the previous version of

  the compiler.