News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

type of variable

Started by JK, April 04, 2021, 01:06:22 AM

Previous topic - Next topic

jj2007

A little demo, using the FpuPush macro (28 matches for if type()... eq):

include \masm32\include\masm32rt.inc
.686
.xmm

include FpuPush.asm   ; (attached)

.data
MyQW QWORD 123467890123467890
MyDW DWORD 111
MyR4 REAL4 333.333
MyR8 REAL8 444.444
MyR10 REAL10 555.555
result REAL8 ?
.code
start:
cls
FpuPush MyQW
fstp result
print real8$(result), " is MyQW", 13, 10

FpuPush MyDW
fstp result
print real8$(result), " is MyDW", 13, 10

FpuPush MyR4
fstp result
print real8$(result), " is MyR4", 13, 10

FpuPush MyR8
fstp result
print real8$(result), " is MyQW", 13, 10

FpuPush MyR10
fstp result
print real8$(result), " is MyR10", 13, 10

movlps xmm0, MyQW
FpuPush xmm0
fstp result
print real8$(result), " is xmm0 (as QWORD)", 13, 10

movlps xmm0, MyR8
FpuPush f:xmm0
fstp result
print real8$(result), " is xmm0 (as REAL8)", 13, 10, 10

inkey "bye"
  exit

end start


Output:
123467890123467890.000000 is MyQW
111.000000 is MyDW
333.333008 is MyR4
444.444000 is MyQW
555.555000 is MyR10
123467890123467890.000000 is xmm0 (as QWORD)
444.444000 is xmm0 (as REAL8)


Of course, Str$(any number) does the three steps silently under the hood.

TouEnMasm


This one can be interesting
Quote
?Type macro typ:req
   LOCAL typtxt
   typtxt equ <>
   for arg,<BYTE,SBYTE,WORD,SWORD,FWORD,DWORD,SDWORD,QWORD,SQWORD,OWORD,REAL4,REAL8,REAL10,TBYTE>
      %if (type (typ)) eq arg
         typtxt equ arg
         exitm <>
      endif
   endm
   exitm typtxt
endm


Fa is a musical note to play with CL

jj2007

Looks good, Yves :thumbsup:

A variant, using a numerical output:

include \masm32\include\masm32rt.inc ; pure Masm32 SDK

?Type macro typ:req
   LOCAL tct
   tct=0
   for arg,<BYTE,SBYTE,WORD,SWORD,FWORD,DWORD,SDWORD,QWORD,SQWORD,OWORD,REAL4,REAL8,REAL10,TBYTE>
tct=tct+1
       %if (type (typ)) eq arg
         exitm <>
      endif
    endm
   exitm %tct
endm

.data
MyDW DWORD 123
MyQW QWORD 456
MySQW SQWORD -123
MyR4 REAL4 123.456

.code
start:
  % echo DW=?Type(MyDW)
  % echo R4=?Type(MyR4)
  % echo QW=?Type(MyQW)
  % echo SQW=?Type(MySQW)
  exit
.err
end start


Output window:
DW=6
R4=11
QW=8
SQW=9

TouEnMasm


The Macro is the principle.
It can be see in action here http://masm32.com/board/index.php?topic=8885.msg97287#msg97287
GLU use a bunch of dword,qword,real4,REAL8 who need to be identify correctly and not mixed,failed is the punishment if a dword is not translated to a real4,REAL8.
C do that automatically,not masm except with the use of TYPE.
The form more simple to use is below.
Quote
CONVERTIR MACRO etiquette:REQ,taille:REQ
         IF QWORD EQ TYPE(etiquette) ;si l'argument "etiquette" est du type QWORD
                  ECHO QWORD
         ENDIF
ENDM
Fa is a musical note to play with CL

jj2007

Windows Data Types:
QuoteLONGLONG    

A 64-bit signed integer. The range is -9223372036854775808 through 9223372036854775807 decimal.

This type is declared in WinNT.h as follows:
Table 4
C++

#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif

QuoteDWORD    A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
This type is declared in IntSafe.h as follows:
typedef unsigned long DWORD;
...
LPDWORD    

A pointer to a DWORD.

This type is declared in WinDef.h as follows:

typedef DWORD *LPDWORD;

So a DWORD is a 32-bit unsigned integer, agreed. And a pointer to a DWORD is also a 32-bit integer, even in x64??
And how do we read the star: a 32-bit integer that is a pointer to a pointer to a DWORD??

Are they completely crazy?

QuoteLPCSTR    

A pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef __nullterminated CONST CHAR *LPCSTR;

Beautiful :tongue:

Another goodie - can you see the difference?
Quote#ifdef _WIN64
typedef HALF_PTR *PHALF_PTR;
#else
typedef HALF_PTR *PHALF_PTR;
#endif

:rolleyes:
Quote#if defined(_WIN64)
    #define POINTER_32 __ptr32
#else
    #define POINTER_32
#endif

TimoVJL

Quote from: jj2007 on April 13, 2021, 12:18:55 PM
Windows Data Types:
QuoteLONGLONG    

A 64-bit signed integer. The range is -9223372036854775808 through 9223372036854775807 decimal.

This type is declared in WinNT.h as follows:
Table 4
C++

#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif

Remember of Windows/386 ? It may come from there, C-compiler and tools didn't have a standard type name for 64 number ?

A some of those crazy things also belongs to optimizers and other tools ?
May the source be with you

jj2007

I really wonder why they need (or want) this type checking madness. I counted 146 different types from the Windows Data Types doc, where about 8 (BYTE, WORD, DWORD, QWORD, OWORD, REAL4, REAL8, REAL10) should be enough to check if the arg is ok:

  1 APIENTRY #define APIENTRY
  2 ATOM typedef WORD ATOM;
  3 BOOL typedef int BOOL;
  4 BOOLEAN typedef BYTE BOOLEAN;
  5 BYTE typedef unsigned char BYTE;
  6 CALLBACK #define CALLBACK
  7 CALLBACK typedef
  8 CHAR typedef char CHAR;
  9 COLORREF typedef DWORD COLORREF;
10 CONST #define CONST
11 DWORD typedef unsigned long DWORD;
12 DWORDLONG typedef unsigned __int64 DWORDLONG;
13 DWORD_PTR typedef ULONG_PTR DWORD_PTR;
14 DWORD32 typedef unsigned int DWORD32;
15 DWORD64 typedef unsigned __int64 DWORD64;
16 FLOAT typedef float FLOAT;
17 HACCEL typedef HANDLE HACCEL;
18 HALF_PTR typedef
19 HBITMAP typedef HANDLE HBITMAP;
20 HBRUSH typedef HANDLE HBRUSH;
21 HCOLORSPACE typedef HANDLE HCOLORSPACE;
22 HCONV typedef HANDLE HCONV;
23 HCONVLIST typedef HANDLE HCONVLIST;
24 HCURSOR typedef HICON HCURSOR;
25 HDDEDATA typedef HANDLE HDDEDATA;
26 HDESK typedef HANDLE HDESK;
27 HDROP typedef HANDLE HDROP;
28 HDWP typedef HANDLE HDWP;
29 HENHMETAFILE typedef HANDLE HENHMETAFILE;
30 HFILE typedef int HFILE;
31 HFONT typedef HANDLE HFONT;
32 HGDIOBJ typedef HANDLE HGDIOBJ;
33 HGLOBAL typedef HANDLE HGLOBAL;
34 HHOOK typedef HANDLE HHOOK;
35 HICON typedef HANDLE HICON;
36 HINSTANCE typedef HANDLE HINSTANCE;
37 HKEY typedef HANDLE HKEY;
38 HLOCAL typedef HANDLE HLOCAL;
39 HMENU typedef HANDLE HMENU;
40 HMETAFILE typedef HANDLE HMETAFILE;
41 HMODULE typedef HINSTANCE HMODULE;
42 HMONITOR typedef
43 HPEN typedef HANDLE HPEN;
44 HRESULT typedef LONG HRESULT;
45 HRGN typedef HANDLE HRGN;
46 HRSRC typedef HANDLE HRSRC;
47 HWINSTA typedef
48 HWND typedef HANDLE HWND;
49 INT_PTR typedef
50 LANGID typedef WORD LANGID;
51 LCID typedef DWORD LCID;
52 LCTYPE typedef DWORD LCTYPE;
53 LGRPID typedef DWORD LGRPID;
54 LONG typedef long LONG;
55 LONGLONG typedef
56 LONG64 typedef __int64 LONG64;
57 LPARAM typedef LONG_PTR LPARAM;
58 LPBOOL typedef BOOL far *LPBOOL;
59 LPBYTE typedef BYTE far *LPBYTE;
60 LPCOLORREF typedef DWORD *LPCOLORREF;
61 LPCSTR typedef __nullterminated CONST CHAR *LPCSTR;
62 LPCTSTR typedef
63 LPCWSTR typedef CONST WCHAR *LPCWSTR;
64 LPDWORD typedef DWORD *LPDWORD;
65 LPHANDLE typedef HANDLE *LPHANDLE;
66 LPINT typedef int *LPINT;
67 LPLONG typedef long *LPLONG;
68 LPSTR typedef CHAR *LPSTR;
69 LPTSTR typede
70 LPWORD typedef WORD *LPWORD;
71 LPWSTR typedef WCHAR *LPWSTR;
72 LRESULT typedef LONG_PTR LRESULT;
73 PBOOL typedef BOOL *PBOOL;
74 PBOOLEAN typedef BOOLEAN *PBOOLEAN;
75 PBYTE typedef BYTE *PBYTE;
76 PCHAR typedef CHAR *PCHAR;
77 PCSTR typedef CONST CHAR *PCSTR;
78 PCTSTR typede
79 PDWORD typedef DWORD *PDWORD;
80 PDWORDLONG typedef DWORDLONG *PDWORDLONG;
81 PDWORD_PTR typedef DWORD_PTR *PDWORD_PTR;
82 PDWORD32 typedef DWORD32 *PDWORD32;
83 PDWORD64 typedef DWORD64 *PDWORD64;
84 PFLOAT typedef FLOAT *PFLOAT;
85 PHALF_PTR typedef H
86 PHKEY typedef HKEY *PHKEY;
87 PINT typedef int *PINT;
88 PINT_PTR typedef INT_PTR *PINT_PTR;
89 PINT8 typedef INT8 *PINT8;
90 PINT16 typedef INT16 *PINT16;
91 PINT32 typedef INT32 *PINT32;
92 PINT64 typedef INT64 *PINT64;
93 PLCID typedef PDWORD PLCID;
94 PLONG typedef LONG *PLONG;
95 PLONGLONG typedef LONGLONG *PLONGLONG;
96 PLONG_PTR typedef LONG_PTR *PLONG_PTR;
97 PLONG32 typedef LONG32 *PLONG32;
98 PLONG64 typedef LONG64 *PLONG64;
99 POINTER_32 #define PO
100 POINTER_UNSIGNED #define POINTER_UNSIGNED
101 PSHORT typedef SHORT *PSHORT;
102 PSIZE_T typedef SIZE_T *PSIZE_T;
103 PSSIZE_T typedef SSIZE_T *PSSIZE_T;
104 PSTR typedef CHAR *PSTR;
105 PTBYTE typedef TBYTE *PTBYTE;
106 PTCHAR typedef TCHAR *PTCHAR;
107 PTSTR typed
108 PUHALF_PTR typedef UI
109 PUINT_PTR typedef UINT_PTR *PUINT_PTR;
110 PUINT8 typedef UINT8 *PUINT8;
111 PUINT16 typedef UINT16 *PUINT16;
112 PUINT32 typedef UINT32 *PUINT32;
113 PUINT64 typedef UINT64 *PUINT64;
114 PULONG typedef ULONG *PULONG;
115 PULONGLONG typedef ULONGLONG *PULONGLONG;
116 PULONG_PTR typedef ULONG_PTR *PULONG_PTR;
117 PULONG32 typedef ULONG32 *PULONG32;
118 PULONG64 typedef ULONG64 *PULONG64;
119 PUSHORT typedef USHORT *PUSHORT;
120 PVOID typedef void *PVOID;
121 PWCHAR typedef WCHAR *PWCHAR;
122 PWORD typedef WORD *PWORD;
123 PWSTR typedef WCHAR *PWSTR;
124 QWORD typedef unsigned __int64 QWORD;
125 SC_HANDLE typedef HANDLE SC_HANDLE;
126 SC_LOCK typedef LPVOID SC_LOCK;
127 SERVICE_STATUS_HANDLE typedef HANDLE SERVICE_STATUS_HANDLE;
128 SHORT typedef short SHORT;
129 SIZE_T typedef ULONG_PTR SIZE_T;
130 SSIZE_T typedef LONG_PTR SSIZE_T;
131 TBYTE typed
132 UHALF_PTR typedef u
133 UINT_PTR typedef
134 UINT16 typedef unsigned short UINT16;
135 UINT32 typedef unsigned int UINT32;
136 UINT64 typedef usigned __int 64 UINT64;
137 ULONG typedef unsigned long ULONG;
138 ULONGLONG typedef u
139 ULONG64 typedef unsigned __int64 ULONG64;
140 UNICODE_STRING typedef struct _UNICODE_STRING
141 USHORT typedef unsigned short USHORT;
142 VOID #define VOID
143 WCHAR typedef wchar_t WCHAR;
144 WINAPI #define WINAPI
145 CALLBACK typedef
146 WPARAM typedef UINT_PTR WPARAM;

LiaoMi

Quote from: jj2007 on April 13, 2021, 12:18:55 PM
Windows Data Types:
QuoteLONGLONG    

A 64-bit signed integer. The range is -9223372036854775808 through 9223372036854775807 decimal.

This type is declared in WinNT.h as follows:
Table 4
C++

#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif

QuoteDWORD    A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
This type is declared in IntSafe.h as follows:
typedef unsigned long DWORD;
...
LPDWORD    

A pointer to a DWORD.

This type is declared in WinDef.h as follows:

typedef DWORD *LPDWORD;

So a DWORD is a 32-bit unsigned integer, agreed. And a pointer to a DWORD is also a 32-bit integer, even in x64??
And how do we read the star: a 32-bit integer that is a pointer to a pointer to a DWORD??

Are they completely crazy?

QuoteLPCSTR    

A pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef __nullterminated CONST CHAR *LPCSTR;

Beautiful :tongue:

Another goodie - can you see the difference?
Quote#ifdef _WIN64
typedef HALF_PTR *PHALF_PTR;
#else
typedef HALF_PTR *PHALF_PTR;
#endif

:rolleyes:
Quote#if defined(_WIN64)
    #define POINTER_32 __ptr32
#else
    #define POINTER_32
#endif

Hi jj2007,

some types are automatically overridden by the C++ compiler, it is important to keep in mind when converting include files. Therefore, in different modes, they have different sizes. For C ++, this is normal practice.

Programming with Types Paperback – 7 Dec. 2019 - https://www.amazon.de/Programming-Types-Vlad-Riscutia/dp/1617296414
QuoteType-related failures are common and can be very costly. Famously, in 1999, NASA's Mars Climate Orbiter burned up in the atmosphere because of an error that could have easily been prevented with typing. By taking advantage of the strong type systems available in most modern programming languages, you can eliminate whole classes of errors.

Programming with Types teaches you type system techniques for writing software that's safe, correct, easy to test and maintain, and that practically documents itself. Master these techniques, and you may even help prevent an interstellar catastrophe!

__ptr32, __ptr64
https://docs.microsoft.com/en-us/cpp/cpp/ptr32-ptr64?view=msvc-160

Microsoft Specific

__ptr32 represents a native pointer on a 32-bit system, while __ptr64 represents a native pointer on a 64-bit system.

The following example shows how to declare each of these pointer types:

C++

Copy
int * __ptr32 p32;
int * __ptr64 p64;

On a 32-bit system, a pointer declared with __ptr64 is truncated to a 32-bit pointer. On a 64-bit system, a pointer declared with __ptr32 is coerced to a 64-bit pointer.

jj2007

Quote from: LiaoMi on April 13, 2021, 08:47:57 PMProgramming with Types teaches you type system techniques for writing software that's safe, correct, easy to test and maintain, and that practically documents itself. Master these techniques, and you may even help prevent an interstellar catastrophe!

That's the theory. Practice is that, with strict typing, you will be flooded with warnings for simple things like SendMessage() - unless you cast all your paras with WPARAM and LPARAM.

Of course, Hutch wants the extreme opposite: pass whatever you like, only script kiddies need PROTOs to hold their hot little hands...

Btw can you explain this one?
#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif

LiaoMi

Checking Parameter Type and Size - Something You May Not Know About the Macro in MASM - https://www.codeproject.com/Articles/1080585/Something-You-May-Not-Know-About-the-Macro-in-MASM

When you pass an argument to a macro procedure, the procedure receives it from the parameter although just a text substitution. Usually, you will check some conditions from the parameter to do something accordingly. Since this happens at assembling time, it means that the assembler would choose some instructions if a condition is satisfied, else provide other instructions for unsatisfied if needed. Definitely, you can check the constant argument values, either in string or number. Yet another useful check perhaps, is based on the parameter type or size for registers and variables. For example, one macro procedure only accepts unsigned integers and bypass signed ones, while the second macro may deal with 16 and 32-bit without for 8 and 64-bit arguments.

1. Argument as a Memory Variable
Let's define three variables here:

.data
   swVal SWORD    1
   wVal  WORD     2
   sdVal SDWORD   3

When applying the TYPE and <code>SIZEOF operators to these variables, we simply have:

mov eax, TYPE swVal     ; 2 bytes
mov eax, SIZEOF swVal   ; 2 bytes
mov eax, TYPE wVal      ; 2 bytes
mov eax, SIZEOF wVal    ; 2 bytes
mov eax, TYPE sdVal     ; 4 bytes
mov eax, SIZEOF sdVal   ; 4 bytes

As seen above, there is no numeric difference either between TYPE and SIZEOF, or between WORD and SWORD. The first four instructions all are moving the byte count 2 to EAX. However, TYPE can do more than just returning byte counts. Let's try to check SWORD type and size with the parameter par:

mParameterTYPE MACRO par
   IF TYPE par EQ TYPE SWORD
      ECHO warning: ** TYPE par is TYPE SWORD
   ELSE
      ECHO warning: ** TYPE par is NOT TYPE SWORD   
   ENDIF
ENDM   

mParameterSIZEOF MACRO par
   IF SIZEOF par EQ SIZEOF SWORD
      ECHO warning: ** SIZEOF par is SIZEOF SWORD
   ELSE
      ECHO warning: ** SIZEOF par is NOT SIZEOF SWORD   
   ENDIF   
ENDM

Then calling two macros by passing the above defined variables

ECHO warning: --- Checking TYPE and SIZEOF for wVal ---
mParameterTYPE wVal
mParameterSIZEOF wVal

ECHO warning: --- Checking TYPE and SIZEOF for swVal ---
mParameterTYPE swVal
mParameterSIZEOF swVal

ECHO warning: --- Checking TYPE and SIZEOF for sdVal ---
mParameterTYPE sdVal
mParameterSIZEOF sdVal


See the following results in Output:


Obviously, the TYPE operator can be used to differentiate the signed or unsigned arguments passed, as SWORD and WORD are different types. While SIZEOF is simply a comparison of byte counts, as SWORD and WORD are both 2 bytes. The last two checks means the type of SDWORD is not SWORD and the size of SDWORD is 4 bytes not 2.

Furthermore, let's make direct checks, since two operators also can apply to data type names here:

mCheckTYPE MACRO
    IF TYPE SWORD EQ TYPE WORD
        ECHO warning: ** TYPE SWORD EQ TYPE WORD
    ELSE
        ECHO warning: ** TYPE SWORD NOT EQ TYPE WORD
    ENDIF
ENDM

mCheckSIZEOF MACRO
    IF SIZEOF SWORD EQ SIZEOF WORD
        ECHO warning: ** SIZEOF SWORD EQ SIZEOF WORD
    ELSE
        ECHO warning: ** SIZEOF SWORD NOT EQ SIZEOF WORD   
    ENDIF
ENDM

The following result is intuitive and straightforward:


2. Argument as a Register
Since an argument can be a register, let's call two previous macros to check its TYPE and SIZEOF:

mParameterTYPE AL
mParameterSIZEOF AL
mParameterTYPE AX
mParameterSIZEOF AX

We receive such messages:


As we see here, for type check, neither AL nor AX (even 16-bit) is signed WORD. Actually, you cannot apply SIZEOF to a register that causes assembling error A2009. You can verify it directly:

mov ebx, SIZEOF al    ; error A2009: syntax error in expression
mov ebx, TYPE al

But which type is for registers? The answer is all registers are unsigned by default. Simply make this:

mParameterTYPE2 MACRO par
   IF TYPE par EQ WORD
      ECHO warning: ** TYPE par is WORD
   ELSE
      ECHO warning: ** TYPE par is NOT WORD   
   ENDIF
ENDM

And call:

mParameterTYPE2 AL   ; 1>MASM : warning : ** TYPE AL is NOT WORD
mParameterTYPE2 AX   ; 1>MASM : warning : ** TYPE AX is WORD
Also notice that I directly use the data type name WORD here equivalent to using TYPE WORD.


3. An Example in Practice
Now let's take a look at a concrete example that requires moving an argument of a 8, 16, or 32-bit singed integer into EAX. To create such a macro, we have to use either the instruction mov or the sign-extension movsx based on the parameter size. The following is one possible solution to compare the parameter's type with the required sizes. The %OUT is the same as ECHO as an alternative.

mParToEAX MACRO intVal
   IF TYPE intVal LE SIZEOF WORD         ;; 8- or 16-bit
      movsx eax, intVal
   ELSEIF TYPE intVal EQ SIZEOF DWORD    ;; 32-bit
      mov eax,intVal
   ELSE
     %OUT Error: ***************************************************************
     %OUT Error: Argument intVal passed to mParToEAX must be 8, 16, or 32 bits.
     %OUT Error:****************************************************************
   ENDIF
ENDM

Test it with different sizes and types for variables and registers:

; Test memory
   mParToEAX bVal       ; BYTE
   mParToEAX swVal      ; SWORD
   mParToEAX wVal       ; WORD
   mParToEAX sdVal      ; SDWORD
   mParToEAX qVal       ; QWORD

; Test registers
   mParToEAX AH         ; 8 bit
   mParToEAX BX         ; 16 bit
   mParToEAX EDX        ; 32 bit
   mParToEAX RDX        ; 64 bit

As expected, the Output shows the following messages to reject qVal reasonably. Also fine is an error reported for RDX, as our 32-bit project doesn't recognize a 64-bit register.


You can try the downloadable code in ParToEAX.asm. Furthermore, let's generate its listing file to see what instructions the assembler has created to substitute macro calls. As expected, bVal, swVal, wVal, and sdVal are good but without qVal; while AH, BX, and EDX good but without RDX:

00000000         .data
00000000 03            bVal  BYTE     3
00000001 FFFC          swVal SWORD   -4
00000003 0005          wVal  WORD     5
00000005 FFFFFFFA      sdVal SDWORD   -6
00000009               qVal  QWORD    7
      0000000000000007

00000000         .code
00000000         main_pe PROC
            ; Test memory
               mParToEAX bVal       ; BYTE
00000000  0F BE 05        1         movsx eax, bVal
      00000000 R
               mParToEAX swVal      ; SWORD
00000007  0F BF 05        1         movsx eax, swVal
      00000001 R
               mParToEAX wVal       ; WORD
0000000E  0F BF 05        1         movsx eax, wVal
      00000003 R
               mParToEAX sdVal      ; SDWORD
00000015  A1 00000005 R     1       mov eax,sdVal
               mParToEAX qVal       ; QWORD

            ; Test registers
               mParToEAX AH         ; 8 bit
0000001A  0F BE C4        1         movsx eax, AH
               mParToEAX BX         ; 16 bit
0000001D  0F BF C3        1         movsx eax, BX
               mParToEAX EDX        ; 32 bit
00000020  8B C2        1            mov eax,EDX
               mParToEAX RDX        ; 64 bit
              1      IF TYPE RDX LE SIZEOF WORD       
AsmCode\ParToEAX.asm(45) : error A2006:undefined symbol : RDX
mParToEAX(1): Macro Called From
  AsmCode\ParToEAX.asm(45): Main Line Code
              1      ELSE
AsmCode\ParToEAX.asm(45) : error A2006:undefined symbol : RDX
mParToEAX(3): Macro Called From
  AsmCode\ParToEAX.asm(45): Main Line Code

               invoke ExitProcess,0
00000029         main_pe ENDP
            END ; main_pe

jj2007

That's all correct, and that's why deb works:

deb 4, "Variables etc", ST(0), ST(1), b:eax, $ecx, $esi, $My$, $$MyWide$, a1, a2, a3, MyDword, MyR8, MyQ, x:xmm0, f:xmm1

Variables etc
ST(0)           1.000000000000000000
ST(1)           3.141592653589793238
b:eax           00000111010110111100110100010101
$ecx            123     <not a pointer>
$esi            Hello World
$My$            Здравствуйте, мир
$$MyWide$       Hello World
a1              111
a2              222
a3              333
MyDword         123456789
MyR8            1234567.890123457
MyQ             1234567890123456789
x:xmm0          00000000 00000000 00000000 075BCD15
f:xmm1          1234567.890123457


But give me a good reason now why anyone would need 100+ different types...

LiaoMi

Quote from: jj2007 on April 13, 2021, 08:56:50 PM
Quote from: LiaoMi on April 13, 2021, 08:47:57 PMProgramming with Types teaches you type system techniques for writing software that's safe, correct, easy to test and maintain, and that practically documents itself. Master these techniques, and you may even help prevent an interstellar catastrophe!

That's the theory. Practice is that, with strict typing, you will be flooded with warnings for simple things like SendMessage() - unless you cast all your paras with WPARAM and LPARAM.

Of course, Hutch wants the extreme opposite: pass whatever you like, only script kiddies need PROTOs to hold their hot little hands...

Btw can you explain this one?
#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif


LONGLONG is an alias, thought experiment:

x64 - LONGLONG = int64 = 8 (Macro)
x32 - LONGLONG = int64 = 4

x64 - LONGLONG = double = 8
x32 - LONGLONG = double = 8 (Macro)

https://en.wikipedia.org/wiki/Double-precision_floating-point_format, double is always 64 bits  :rolleyes:

jj2007

Correct, double is always 64 bits; but the same applies to a LONGLONG. The only problem is that...

#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif


...defines a LONGLONG as a REAL8, which is obviously bs*t.

If you are up for some fun: WINAPI is not the only way to define a 'callable' address in a Windows DLL. The type checking fanatics have invented many more:
#define STDMETHODCALLTYPE       __stdcall
#define STDMETHODVCALLTYPE      __cdecl
#define STDAPICALLTYPE          __stdcall
#define STDAPIVCALLTYPE         __cdecl
...
#define STDAPICALLTYPE          __export __stdcall
#define STDAPIVCALLTYPE         __export __cdecl
#define CDECL_NON_WVMPURE __cdecl


Full list attached.

LiaoMi

Quote from: jj2007 on April 13, 2021, 09:03:26 PM

But give me a good reason now why anyone would need 100+ different types...

Data type abstraction and dynamic overriding
https://en.wikipedia.org/wiki/Strong_and_weak_typing

QuoteThus, strong type checking helps prevent errors and enhances reliability.
for handling abstract structures.

QuoteCorrect, double is always 64 bits; but the same applies to a LONGLONG. The only problem is that...

Code: [Select]
#if !defined(_M_IX86)
typedef __int64 LONGLONG;
#else
typedef double LONGLONG;
#endif

...defines a LONGLONG as a REAL8, which is obviously bs*t.

These values can be overridden, i.e. you need to look specifically when the type does not match the given one.

LiaoMi

Quote from: jj2007 on April 13, 2021, 08:56:50 PM
Of course, Hutch wants the extreme opposite: pass whatever you like, only script kiddies need PROTOs to hold their hot little hands...

I had such a problem  :biggrin:  :tongue:, just when the prototypes do not match in the parameters of the function. This was a problem in the example from Hutch. But there is no point in arguing here, because assembler moves away from strong typing, if we discard abstract data.

Quote from: jj2007 on April 13, 2021, 08:56:50 PM
That's the theory. Practice is that, with strict typing, you will be flooded with warnings for simple things like SendMessage() - unless you cast all your paras with WPARAM and LPARAM.

This is a big problem in the C++ language, but if you understand all the rules of the language, and if you understand the internal structure, it will become easier.

Quote from: jj2007 on April 13, 2021, 07:26:53 PM
I really wonder why they need (or want) this type checking madness. I counted 146 different types from the Windows Data Types doc, where about 8 (BYTE, WORD, DWORD, QWORD, OWORD, REAL4, REAL8, REAL10) should be enough to check if the arg is ok:

  1 APIENTRY #define APIENTRY
  2 ATOM typedef WORD ATOM;
  3 BOOL typedef int BOOL;
  4 BOOLEAN typedef BYTE BOOLEAN;
  5 BYTE typedef unsigned char BYTE;
  6 CALLBACK #define CALLBACK
  7 CALLBACK typedef
  8 CHAR typedef char CHAR;
  9 COLORREF typedef DWORD COLORREF;
10 CONST #define CONST
11 DWORD typedef unsigned long DWORD;
12 DWORDLONG typedef unsigned __int64 DWORDLONG;
13 DWORD_PTR typedef ULONG_PTR DWORD_PTR;
14 DWORD32 typedef unsigned int DWORD32;
15 DWORD64 typedef unsigned __int64 DWORD64;
16 FLOAT typedef float FLOAT;
17 HACCEL typedef HANDLE HACCEL;
18 HALF_PTR typedef
19 HBITMAP typedef HANDLE HBITMAP;
20 HBRUSH typedef HANDLE HBRUSH;
21 HCOLORSPACE typedef HANDLE HCOLORSPACE;
22 HCONV typedef HANDLE HCONV;
23 HCONVLIST typedef HANDLE HCONVLIST;
24 HCURSOR typedef HICON HCURSOR;
25 HDDEDATA typedef HANDLE HDDEDATA;
26 HDESK typedef HANDLE HDESK;
27 HDROP typedef HANDLE HDROP;
28 HDWP typedef HANDLE HDWP;
29 HENHMETAFILE typedef HANDLE HENHMETAFILE;
30 HFILE typedef int HFILE;
31 HFONT typedef HANDLE HFONT;
32 HGDIOBJ typedef HANDLE HGDIOBJ;
33 HGLOBAL typedef HANDLE HGLOBAL;
34 HHOOK typedef HANDLE HHOOK;
35 HICON typedef HANDLE HICON;
36 HINSTANCE typedef HANDLE HINSTANCE;
37 HKEY typedef HANDLE HKEY;
38 HLOCAL typedef HANDLE HLOCAL;
39 HMENU typedef HANDLE HMENU;
40 HMETAFILE typedef HANDLE HMETAFILE;
41 HMODULE typedef HINSTANCE HMODULE;
42 HMONITOR typedef
43 HPEN typedef HANDLE HPEN;
44 HRESULT typedef LONG HRESULT;
45 HRGN typedef HANDLE HRGN;
46 HRSRC typedef HANDLE HRSRC;
47 HWINSTA typedef
48 HWND typedef HANDLE HWND;
49 INT_PTR typedef
50 LANGID typedef WORD LANGID;
51 LCID typedef DWORD LCID;
52 LCTYPE typedef DWORD LCTYPE;
53 LGRPID typedef DWORD LGRPID;
54 LONG typedef long LONG;
55 LONGLONG typedef
56 LONG64 typedef __int64 LONG64;
57 LPARAM typedef LONG_PTR LPARAM;
58 LPBOOL typedef BOOL far *LPBOOL;
59 LPBYTE typedef BYTE far *LPBYTE;
60 LPCOLORREF typedef DWORD *LPCOLORREF;
61 LPCSTR typedef __nullterminated CONST CHAR *LPCSTR;
62 LPCTSTR typedef
63 LPCWSTR typedef CONST WCHAR *LPCWSTR;
64 LPDWORD typedef DWORD *LPDWORD;
65 LPHANDLE typedef HANDLE *LPHANDLE;
66 LPINT typedef int *LPINT;
67 LPLONG typedef long *LPLONG;
68 LPSTR typedef CHAR *LPSTR;
69 LPTSTR typede
70 LPWORD typedef WORD *LPWORD;
71 LPWSTR typedef WCHAR *LPWSTR;
72 LRESULT typedef LONG_PTR LRESULT;
73 PBOOL typedef BOOL *PBOOL;
74 PBOOLEAN typedef BOOLEAN *PBOOLEAN;
75 PBYTE typedef BYTE *PBYTE;
76 PCHAR typedef CHAR *PCHAR;
77 PCSTR typedef CONST CHAR *PCSTR;
78 PCTSTR typede
79 PDWORD typedef DWORD *PDWORD;
80 PDWORDLONG typedef DWORDLONG *PDWORDLONG;
81 PDWORD_PTR typedef DWORD_PTR *PDWORD_PTR;
82 PDWORD32 typedef DWORD32 *PDWORD32;
83 PDWORD64 typedef DWORD64 *PDWORD64;
84 PFLOAT typedef FLOAT *PFLOAT;
85 PHALF_PTR typedef H
86 PHKEY typedef HKEY *PHKEY;
87 PINT typedef int *PINT;
88 PINT_PTR typedef INT_PTR *PINT_PTR;
89 PINT8 typedef INT8 *PINT8;
90 PINT16 typedef INT16 *PINT16;
91 PINT32 typedef INT32 *PINT32;
92 PINT64 typedef INT64 *PINT64;
93 PLCID typedef PDWORD PLCID;
94 PLONG typedef LONG *PLONG;
95 PLONGLONG typedef LONGLONG *PLONGLONG;
96 PLONG_PTR typedef LONG_PTR *PLONG_PTR;
97 PLONG32 typedef LONG32 *PLONG32;
98 PLONG64 typedef LONG64 *PLONG64;
99 POINTER_32 #define PO
100 POINTER_UNSIGNED #define POINTER_UNSIGNED
101 PSHORT typedef SHORT *PSHORT;
102 PSIZE_T typedef SIZE_T *PSIZE_T;
103 PSSIZE_T typedef SSIZE_T *PSSIZE_T;
104 PSTR typedef CHAR *PSTR;
105 PTBYTE typedef TBYTE *PTBYTE;
106 PTCHAR typedef TCHAR *PTCHAR;
107 PTSTR typed
108 PUHALF_PTR typedef UI
109 PUINT_PTR typedef UINT_PTR *PUINT_PTR;
110 PUINT8 typedef UINT8 *PUINT8;
111 PUINT16 typedef UINT16 *PUINT16;
112 PUINT32 typedef UINT32 *PUINT32;
113 PUINT64 typedef UINT64 *PUINT64;
114 PULONG typedef ULONG *PULONG;
115 PULONGLONG typedef ULONGLONG *PULONGLONG;
116 PULONG_PTR typedef ULONG_PTR *PULONG_PTR;
117 PULONG32 typedef ULONG32 *PULONG32;
118 PULONG64 typedef ULONG64 *PULONG64;
119 PUSHORT typedef USHORT *PUSHORT;
120 PVOID typedef void *PVOID;
121 PWCHAR typedef WCHAR *PWCHAR;
122 PWORD typedef WORD *PWORD;
123 PWSTR typedef WCHAR *PWSTR;
124 QWORD typedef unsigned __int64 QWORD;
125 SC_HANDLE typedef HANDLE SC_HANDLE;
126 SC_LOCK typedef LPVOID SC_LOCK;
127 SERVICE_STATUS_HANDLE typedef HANDLE SERVICE_STATUS_HANDLE;
128 SHORT typedef short SHORT;
129 SIZE_T typedef ULONG_PTR SIZE_T;
130 SSIZE_T typedef LONG_PTR SSIZE_T;
131 TBYTE typed
132 UHALF_PTR typedef u
133 UINT_PTR typedef
134 UINT16 typedef unsigned short UINT16;
135 UINT32 typedef unsigned int UINT32;
136 UINT64 typedef usigned __int 64 UINT64;
137 ULONG typedef unsigned long ULONG;
138 ULONGLONG typedef u
139 ULONG64 typedef unsigned __int64 ULONG64;
140 UNICODE_STRING typedef struct _UNICODE_STRING
141 USHORT typedef unsigned short USHORT;
142 VOID #define VOID
143 WCHAR typedef wchar_t WCHAR;
144 WINAPI #define WINAPI
145 CALLBACK typedef
146 WPARAM typedef UINT_PTR WPARAM;


Here's a logic abstraction for the compiler. We have to live with it, because Windows is not written in assembler  :biggrin: