在 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
不考虑代码可读性、性能和操作系统版本,
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