News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Suggestion with MSVCRT code.

Started by hutch--, June 06, 2005, 04:59:13 AM

Previous topic - Next topic

GregL

Hutch,

I know, I ran into the same thing. I thought that would work too, but it doesn't. I think the C compiler replaces the "\t" or "\n" in the string with the actual character code like 9 or 10 at compile-time, so in MASM we have to manually do what the C compiler automatically does.


GregL

More input/output macros that use C run-time library functions. I know MASM32 already has macros that do these things. I'm just exploring what can be done with the CRT functions in MASM32.


.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

;-----------------------------------------------------
linein MACRO   
    ; Usage: mov eax, linein()
    LOCAL buffer
    .data?
        buffer BYTE 96 dup(?)
    IFNDEF strFmt   
    .data
        strFmt BYTE "%s", 0
    ENDIF
    IFNDEF Cr
    .data
        dwNewLine DWORD 10
    ENDIF   
    .code   
    invoke crt_fgets, ADDR buffer, SIZEOF buffer, crt__iob
    push eax
    invoke crt_strchr, ADDR buffer, dwNewLine
    .if eax
        mov BYTE PTR [eax], 0   ; remove the newline from buffer
    .endif   
    pop eax
    EXITM <eax>
ENDM   
;-----------------------------------------------------
lineout MACRO pStr
    ; Usage: lineout chr$("Hello")
    ; Replaces the trailing nul character
    ; with a linefeed.
    IFNB <pStr>
        invoke crt_puts, pStr
    ELSE
        invoke crt_puts, chr$(0)
    ENDIF
ENDM
;-----------------------------------------------------
printstr MACRO pStr:req
    ;Usage: printstr chr$("Hello")
    invoke crt_printf, pStr
ENDM   
;-----------------------------------------------------
WaitKey MACRO
    lineout
    printstr chr$("Press any key to exit...")
    invoke wait_key
    lineout
ENDM
;-----------------------------------------------------

.DATA

    lpInput DWORD 0

.CODE

start:
   
    lineout chr$("Input/Output Test")
    lineout
    printstr chr$("Enter some text: ")
    mov lpInput, linein()
    printstr chr$("You entered:     ")
    lineout lpInput
       
    WaitKey
    invoke ExitProcess, 0

end start


GregL

An example of using floating-point CRT functions.


.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

Sine       PROTO degrees:PTR REAL8,     sin:PTR REAL8
Cosine     PROTO degrees:PTR REAL8,     cos:PTR REAL8
Tangent    PROTO degrees:PTR REAL8,     tan:PTR REAL8
Arcsine    PROTO sin    :PTR REAL8, degrees:PTR REAL8
Arccosine  PROTO cos    :PTR REAL8, degrees:PTR REAL8
Arctangent PROTO tan    :PTR REAL8, degrees:PTR REAL8
inputR4    PROTO pR4    :PTR REAL4
inputR8    PROTO pR8    :PTR REAL8
inputR10   PROTO pR10   :PTR REAL10

;---------------------------------------
; macros
;---------------------------------------
printf MACRO pszFmt, args:VARARG
    IFB <args>
        IFB <pszFmt>
            invoke crt_printf, chr$(13,10)
        ELSE   
            invoke crt_printf, pszFmt
        ENDIF
    ELSE
        invoke crt_printf, pszFmt, args
    ENDIF   
ENDM   
;---------------------------------------
WaitKey MACRO
    printf chr$(13,10,"Press any key to continue...")
    call wait_key
    printf
ENDM
;---------------------------------------

.DATA

    dblDegrees     REAL8   0.0
    dblSine        REAL8   0.0
    dblCosine      REAL8   0.0
    dblTangent     REAL8   0.0
           
.CODE

start:

    printf chr$("Enter angle in degrees: ")
    invoke inputR8, ADDR dblDegrees
       
    printf
    printf chr$("Angle                 = %9.6lf degrees",13, 10), dblDegrees
                   
    invoke Sine, ADDR dblDegrees, ADDR dblSine
    invoke Cosine, ADDR dblDegrees, ADDR dblCosine
    invoke Tangent, ADDR dblDegrees, ADDR dblTangent
       
    printf
    printf chr$("Sine(%.0lf)              = %8.6lf", 13, 10), dblDegrees, dblSine
    printf chr$("Cosine(%.0lf)            = %8.6lf", 13, 10), dblDegrees, dblCosine
    printf chr$("Tangent(%.0lf)           = %8.6lf", 13, 10), dblDegrees, dblTangent
    printf
           
    invoke Arcsine, ADDR dblSine, ADDR dblDegrees
    printf chr$("Arcsine(%8.6lf)     = %9.6lf degrees", 13, 10), dblSine, dblDegrees
 
    invoke Arccosine, ADDR dblCosine, ADDR dblDegrees
    printf chr$("Arccosine(%8.6lf)   = %9.6lf degrees", 13, 10), dblCosine, dblDegrees
   
    invoke Arctangent, ADDR dblTangent, ADDR dblDegrees
    printf chr$("Arctangent(%8.6lf)  = %9.6lf degrees", 13, 10), dblTangent, dblDegrees
               
    WaitKey
       
    invoke ExitProcess, 0

;======================================================
; procedures
;======================================================
Sine PROC degrees:PTR REAL8, sin:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_sin, radians    ;result in ST(0)
        mov     eax, sin
        fstp    REAL8 PTR [eax]
        fwait
        ret
Sine ENDP
;======================================================
Cosine PROC degrees:PTR REAL8, cos:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_cos, radians    ;result in ST(0)
        mov     eax, cos
        fstp    REAL8 PTR [eax]
        fwait
        ret
Cosine ENDP
;======================================================
Tangent PROC degrees:PTR REAL8, tan:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_tan, radians    ;result in ST(0)
        mov     eax, tan
        fstp    REAL8 PTR [eax]
        fwait
        ret
Tangent ENDP
;======================================================
Arcsine PROC sin:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF       
    .CODE
        mov     eax, sin
        invoke  crt_asin, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arcsine ENDP
;======================================================
Arccosine PROC cos:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, cos
        invoke  crt_acos, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arccosine ENDP
;======================================================
Arctangent PROC tan:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, tan
        invoke  crt_atan, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arctangent ENDP
;======================================================
inputR4 PROC pR4:PTR REAL4
    invoke crt_scanf, chr$("%f"), pR4
    ret
inputR4 ENDP
;======================================================
inputR8 PROC pR8:PTR REAL8
    invoke crt_scanf, chr$("%lf"), pR8
    ret
inputR8 ENDP
;======================================================
inputR10 PROC pR10:PTR REAL10
    LOCAL r8:REAL8
    invoke crt_scanf, chr$("%lf"), ADDR r8
    mov eax, pR10
    finit
    fld r8
    fstp REAL10 PTR [eax]
    fwait
    ret
inputR10 ENDP
;======================================================
end start

   

Vortex

Nice work.

Technically, what's the difference between msvcrt.dll and crtdll.dll ?

GregL

#64
Vortex,

Good question, it's not real clear in my mind either. Here are some links I found:

    How To Use the C Run-Time

    How to link with the correct C Run-Time (CRT) library

    C Run-Time Libraries


I have also been trying out using pocrt, as it supports some handy C99 stuff that msvcrt does not. With it we're back to the naming conflicts problem with the MASM32 library. How Hutch modified the .inc and .lib for msvcrt is beyond me at this point.   


GregL

Hutch (and anyone else that is interested),

Regarding the sprintf conversion macros:

Something I noticed, if a REAL8 is passed to the real4$ macro, the buffer could possibly overflow since the REAL4 gets converted to a REAL8 for the function call. Why am I dong this? Because the C compiler generates code to convert the REAL4 to a REAL8 for the call to sprintf. If you pass sprintf a REAL4 it doesn't work correctly.

  1) increase the buffer to 320 to allow for DBL_MAX.
  2) Somehow only allow a REAL4 to be passed to the macro.

I also noticed that the buffers in all the macros should be initialized to 0 so that if sprintf fails the buffer string is terminated.

What do you think? I'd be glad to make these changes.


hutch--

Greg,

There is a toy in the latest service pack that solves this problem. MAKECIMP will work on any list of procedure names to produce an include file and a LIB file. It automatically prepends "crt_" to the function names in the include but all you need to do is do a global replace of "crt_" with another prefix and you solve the name duplication problem.

Initialising the buffer is a good idea, all you need to do is write a single zero as the first byte in the buffer, it does not ned to be zero filled.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

#67
Hutch,

Thanks for pointing me to MAKECIMP, I had forgotten all about it. I was able to make a pocrt.inc and pocrt.lib with it and they work. The only drawback is pocrt.dll isn't already on every Windows PC like msvcrt.dll is.

Would you recommend changing the  .data?  section to  .data  or add a  mov buffer[0],0  to the code?

In the real4$ macro, if I use the VarR8FromR4 API function, I get an assembly error if I pass it anything other than a REAL4, thanks to invoke.


GregL

#68
Well it's getting late here, so I'll post what I have done with the sprintf macros.


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc
include c:\masm32\include\oleaut32.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib
includelib c:\masm32\lib\oleaut32.lib

;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, ubytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, sbytevalue
        movsx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, xbytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, uwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, swordvalue
        movsx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, xwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, udwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR udwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt BYTE "%ld", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, sdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR sdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, xdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR xdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke VarR8FromR4, r4value, ADDR r8value
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    REAL10 PTR r10value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
WaitKey MACRO
    LOCAL szCrLf, szPAK
    .data
        szCrLf BYTE 13, 10, 0
        szPAK  BYTE 13, 10, "Press any key to continue...", 0
    .code   
        invoke crt_printf, ADDR szPAK
        call crt__getch
        .if (eax == 0) || (eax == 0E0h)
            call crt__getch
        .endif
        invoke crt_printf, ADDR szCrLf
ENDM
;; ----------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483648                ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775808        ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
       
    invoke crt_puts, ubyte$(ubyMax)
    invoke crt_puts, ubyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sbyte$(sbyMax)
    invoke crt_puts, sbyte$(sbyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xbyte$(ubyMax)
    invoke crt_puts, xbyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uword$(uwdMax)
    invoke crt_puts, uword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sword$(swdMax)
    invoke crt_puts, sword$(swdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xword$(uwdMax)
    invoke crt_puts, xword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, udword$(udwMax)
    invoke crt_puts, udword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sdword$(sdwMax)
    invoke crt_puts, sdword$(sdwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xdword$(udwMax)
    invoke crt_puts, xdword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uqword$(uqwMax)
    invoke crt_puts, uqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sqword$(sqwMax)
    invoke crt_puts, sqword$(sqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xqword$(uqwMax)
    invoke crt_puts, xqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real4$(r4Max)
    invoke crt_puts, real4$(r4Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real8$(r8Max)
    invoke crt_puts, real8$(r8Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real10$(r10Max)
    invoke crt_puts, real10$(r10Min)
           
    WaitKey
         
    invoke ExitProcess, 0

end start



GregL

On second thought VarR8FromR4 is not very good because it requires an oddball .inc and .lib (oleaut32).  ::)

I'm going to sleep on it.


hutch--

Greg,

I would be inclined to set the buffer to zero dynamically rather than set the section to initialised data as it is more size efficient.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,



Regarding initializing the buffer:

  Good, that's what I thought too, done.



Regarding the possible buffer overflow if a REAL8 is passed to the real4$ macro:

1) Increase the buffer size to 320.

2) Use VarR8FromR4 for the conversion. If called with invoke it causes an assembly-time error if the wrong data type is passed. It requires including oleaut32.inc/.lib.

real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke VarR8FromR4, r4value, ADDR r8value
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM


3) Force the FPU to load a REAL4. It solves the possible buffer overflow but does not cause an assembly-time error.

real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    REAL4 PTR r4value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM


If someone has a better idea please speak up.

I prefer #2, but it's up to you Hutch.


hutch--

Greg,

This may be a simple solution and it means the user must get the data type correct.


    tst4 MACRO arg
      IF op_type(arg) EQ 4                  ;; if integer register
        echo -------------------------------
        echo REAL4 Memory operand expected.
        echo Integer register not allowed in
        echo this context.
        echo -------------------------------
        .err
      ENDIF
      IF SIZEOF arg NE 4                    ;; if not 4 bytes
        echo -------------------------------
        echo data size error, requires REAL4
        echo -------------------------------
        .err
      ENDIF
    ENDM

Tested with this code.

    tst4 FP4(1234.5678)

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,

I like it. Your experience with MASM is showing, and my lack of experience with MASM is showing. :bg I had never used .ERR before. That method could be used in the other macros, but I'm not sure they need it.

Here are the sprintf conversion macros with my concerns addressed:

;; ----------------------------------------------
tst4 MACRO arg
    IF op_type(arg) EQ 4                  ;; if integer register
        echo -------------------------------
        echo REAL4 Memory operand expected.
        echo Integer register not allowed in
        echo this context.
        echo -------------------------------
       .err
    ENDIF
    IF SIZEOF arg NE 4                    ;; if not 4 bytes
        echo -------------------------------
        echo data size error, requires REAL4
        echo -------------------------------
       .err
  ENDIF
ENDM
;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, ubytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, sbytevalue
        movsx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, xbytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, uwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, swordvalue
        movsx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, xwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, udwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR udwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt BYTE "%ld", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, sdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR sdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, xdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR xdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        tst4   r4value
        finit
        fld    r4value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    r10value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------



Howard

Hi

QuoteThis is an unrelated question. Whenever I have tried to use the internal notation within a quoted string of \t or \n I only ever get those characters as literals in the displayed string and not the TAB or CRLF. Am I missing something in how I format the strings.


Not having followed things too closely this may be a foolish comment, but normally to get an escape sequence recognized in a string in C I used to have to write it as "\\t" instead of "\t". Have you tried that?

Howard