在 RPGLE 中移动操作码和 C API

MOVE opcode and C APIs in RPGLE

考虑代码可读性、性能和操作系统版本,
MOVE 操作码和 C API 如 ATOI 有什么区别?
MOVE 内部如何运作?

示例:

MOVE      ALPHAFLD  NUMRCFLD
EVAL      NUMRCFLD = ATOI(ALPHAFLD)

旧 O.S。 (< V3R7) 我什么时候应该使用 MOVE 什么时候应该使用 C APIs?

这个问题可能是题外话,因为它可能是基于意见...

但我会告诉你我的答案。

首先,atoi()MOVE 不同。您还需要 atol()atof() 来处理 MOVE 可以处理的所有情况。鉴于小数的数量,atof() 尤为重要,而 AS/400 处理。但是 atof() 并不是一个很好的选择,因为浮点数与固定小数的不精确性。

但是 MOVE 也不是那么好。例如,它不能处理负数。

如果您真的坚持使用旧版本 OS/400。我建议 IBM RPG IV 编译器开发人员 Barbara Morris 的例程...取自 the Midrange Wiki

     H NOMAIN

      * Copy prototype for procedure getNum
     D/COPY GETNUM_PR

      *-------------------------------------------------------
      * getNum - see GETNUM_PR for details
      *-------------------------------------------------------
     p getNum          b                   export
     D getNum          pi            30p 9
     D  string                      100a   const varying
     D  decCommaParm                  2a   const options(*nopass)
     D  curSymParm                    1a   const options(*nopass)

      * defaults for optional parameters
     D decComma        s              2a   inz('.,')
     D cursym          s              1a   inz(' ')

     D result          s             30s 9 inz(0)

     D sign            s              1a   inz('+')
     D i               s             10i 0
     D len             s             10i 0
     D c               s              1a

      * override defaults if optional parameters were passed
     C                   if        %parms > 1
     C                   eval      decComma = decCommaParm
     C                   endif

     C                   if        %parms > 2
     C                   eval      cursym = cursymParm
     C                   endif

      * call getNumAny to do the work
     C                   callp     getNumAny (string
     C                                      : %addr(result)
     C                                      : %len(result)
     C                                      : %decpos(result)
     C                                      : decComma
     C                                      : curSym)

     C                   return    result
     p getNum          e

      *-------------------------------------------------------
      * getNumAny
      *-------------------------------------------------------
     p getNumAny       b                   export
     D getNumAny       pi
     D  string                      100a   const varying
     D  result                         *   const
     D  digits                       10i 0 const
     D  decimals                     10i 0 const
     D  decComma                      2a   const options(*nopass)
     D  currency                      1a   const options(*nopass)

      * defaults for optional parameters
     D decPoint        s              1a   inz('.')
     D comma           s              1a   inz(',')
     D cursym          s              1a   inz(' ')
      * structure for building result
     D resChars        s             30a   based(result)
      * variables for gathering digit information
      * pNumPart points to the area currently being gathered
      * (the integer part or the decimal part)
     D pNumPart        s               *
     D numPart         s             30a   varying based(pNumPart)
     D intPart         s             30a   varying inz('')
     D decPart         s             30a   varying inz('')
      * other variables
     D intStart        s             10i 0
     D decStart        s             10i 0
     D signByte        s              1a   based(pSignByte)
     D sign            s              1a   inz('+')
     D i               s             10i 0
     D len             s             10i 0
     D c               s              1a

      * override defaults if optional parameters were passed
     C                   if        %parms > 4
     C                   eval      decPoint = %subst(decComma : 1 : 1)
     C                   eval      comma    = %subst(decComma : 2 :1)
     C                   endif

     C                   if        %parms > 5
     C                   eval      cursym = currency
     C                   endif

      * initialization
     C                   eval      len = %len(string)
      * begin reading the integer part
     C                   eval      pNumPart = %addr(intPart)

      * loop through characters
     C                   do        len           i
     C                   eval      c = %subst(string : i : 1)

     C                   select
      * ignore blanks, digit separator, currency symbol
     C                   when      c = comma or c = *blank or c = cursym
     C                   iter
      * decimal point: switch to reading the decimal part
     C                   when      c = decPoint
     C                   eval      pNumPart = %addr(decPart)
     C                   iter
      * sign: remember the most recent sign
     C                   when      c = '+' or c = '-'
     C                   eval      sign = c
     C                   iter
      * more signs: cr, CR, () are all negative signs
     C                   when      c = 'C' or c = 'R' or
     C                             c = 'c' or c = 'r' or
     C                             c = '(' or c = ')'
     C                   eval      sign = '-'
     C                   iter
      * a digit: add it to the current build area
     C                   other
     C                   eval      numPart = numPart + c

     C                   endsl
     C                   enddo

      * make sure that there is no overflow
     C                   if        %len(decPart) > decimals
     C                             or %len(decPart) + %len(intPart) > digits
      * Force an overflow exception
     C                   z-add     *hival        overflowSrc       5 0
     C                   z-add     0             overflowTgt       4 0
     C                   eval      overflowTgt = overflowSrc
     C                   endif

      * initialize the result to all zeros
     C                   eval      %subst(resChars : 1 : digits) = *zeros
      * copy the digit strings into the correct positions in the
      * zoned variable, using the character overlay
     C                   eval      decStart = digits - decimals + 1
     C                   eval      intStart = decStart - %len(intPart)
     C                   eval      %subst(resChars
     C                                  : intStart
     C                                  : %len(intPart))
     C                               = intPart
     C                   eval      %subst(resChars
     C                                  : decStart
     C                                  : %len(decPart))
     C                               = decPart

      * if the sign is negative, make the result negative
     C                   if        sign = '-'

     C                   eval      pSignByte = %addr(resChars) + digits - 1
      * Change the sign zone from x'f' to x'd' (b'1111' to b'1101')
      * using a mask of x'2' (b'0010')
     C                   bitoff    X'20'         signByte

     C                   endif

     p getNumAny       e
-----------------------------------------------------------
      * Prototype file
     D getNum          pr            30p 9
     D  string                      100a   const varying
     D  decComma                      2a   const options(*nopass)
     D  currency                      1a   const options(*nopass)

     D getNumAny       pr
     D  string                      100a   const varying
     D  result                         *   const
     D  digits                       10i 0 const
     D  decimals                     10i 0 const
     D  decComma                      2a   const options(*nopass)
     D  currency                      1a   const options(*nopass)  


      *---------------------------------------------------------    
      * getNum - procedure to read a number from a string           
      *          and return a 30p 9 value                           
      * Parameters:                                                 
      *   I:      string   - character value of number              
      *   I:(opt) decComma - decimal point and digit separator      
      *   I:(opt) currency - currency symbol for monetary amounts   
      * Returns:  packed(30,9)                                      
      *                                                             
      * Parameter details:                                          
      *   string:   the string may have                             
      *             - blanks anywhere                               
      *             - sign anywhere                                 
      *               accepted signs are: + - cr CR ()              
      *               (see examples below)                          
      *             - digit separators anywhere                     
      *             - currency symbol anywhere                      
      *   decComma: if not passed, this defaults to                 
      *                 decimal point   = '.'                       
      *                 digit separator = ','                       
      *   currency: if not passed, defaults to ' '                  
      *                                                             
      * Examples of input and output (x means parm not passed):     
      *                                                            
      *        string         | dec | sep | cursym |   result      
      *        ---------------+-----+-----+--------+------------   
      *          123          | x   | x   | x      |   123         
      *          +123         | x   | x   | x      |   123         
      *          123+         | x   | x   | x      |   123         
      *          -123         | x   | x   | x      |   -123        
      *          123-         | x   | x   | x      |   -123        
      *          (123)        | x   | x   | x      |   -123        
      *          12,3         | ,   | .   | x      |   12.3        
      *          12.3         | x   | x   | x      |   12.3        
      *          1,234,567.3  | x   | x   | x      |   1234567.3   
      *          ,234,567.3 | .   | ,   | $      |   1234567.3   
      *          .234.567,3 | ,   | .   | $      |   1234567.3   
      *          123.45CR     | x   | x   | x      |   -123.45     
      *                                                            
      * Author: Barbara Morris, IBM Toronto Lab                    
      * Date:   March, 2000    

Barbara 也参与了相关讨论,上面的代码发布在 comp.sys.ibm.as400.misc newsgroup

atoi() 和 atof() "always" 可用。但是自 2002 年左右的 V5R2 以来,RPG 程序员已经能够使用 %INT/%INTH 或 %DEC/%DECH 将字符串转换为数字。%DECH 和 %INTH 进行舍入。

MOVE 有时会以一种奇怪的方式处理数字。例如,假设您有一个具有 5 位数字和 1 个小数位的变量,当前值为 9876.5。现在您将值“123”移动到该变量。试试这段代码,看看变量 "num" 中有什么奇怪的结果。提示:不是 123.

 D num             s              5p 1 inz(9876.5) 
 D msg             s             20                
 C                   move      '123'         num   
 C                   eval      msg = %char(num)    
 C     msg           dsply                         
 C                   return