The MASM Forum

General => The Campus => Topic started by: JK on April 04, 2021, 01:06:22 AM

Title: type of variable
Post by: JK on April 04, 2021, 01:06:22 AM
How could i retrieve the type of a variable in code or in a macro?

The "TYPE" operator returns the size of a register or variable in bytes, but there are still ambiguities. A REAL4 returns 4, which is the same as for a DWORD. The same goes for REAL8 and QWORD and for REAL10 and TWORD. A structure of 16 bytes size (e.g RECT) cannot be distinguished from an OWORD.

So how to decide for sure what is what (a structure, a REAL4/8/10, an integer variable of DWORD, QWORD, TWORD or QWORD size)?


JK
Title: Re: type of variable
Post by: Vortex on April 04, 2021, 01:37:16 AM
QuoteTesting for Argument Type and Environment

Macros can expand conditional blocks of code by testing for argument type with the OPATTR operator. OPATTR returns a single word constant that indicates the type and scope of an expression, like this:

OPATTR expression

If expression is not valid or is forward-referenced, OPATTR returns a 0. Otherwise, the return value incorporates the bit flags shown in the table below.

OPATTR serves as an enhanced version of the .TYPE operator, which returns only the low byte (bits 0 - 7) shown in the table. Bits 11 - 15 of the return value are undefined.

Bit Set If expression


0 References a code label

1 Is a memory variable or has a relocatable data label

2 Is an immediate value

3 Uses direct memory addressing

4 Is a register value

5 References no undefined symbols and is without error

6 Is relative to SS

7 References an external label

8 - 10 Has the following language type: 000 - No language type 001 - C 010 - SYSCALL 011 - STDCALL 100 - Pascal 101 - FORTRAN 110 - Basic

http://www.massmind.org/techref/language/masm/masmc09.htm
Title: Re: type of variable
Post by: JK on April 04, 2021, 02:53:55 AM
Thanks, i know "OPATTR", but it cannot solve my problem.

Suppose i have an argument of a procedure and i want to process this argument in a macro. Different types of arguments would require different processing. I would like to tell from the argument alone, what type of argument it is. The "TYPE" operator allows only for a limited decision, i cannot distinguish e.g between "DWORD" and "REAL4", because "4" is returned for both.


Title: Re: type of variable
Post by: jj2007 on April 04, 2021, 04:46:07 AM
Check \Masm32\MasmBasic\MasmBasic.inc for the string elseif type(tmp$) eq
Title: Re: type of variable
Post by: nidud on April 04, 2021, 05:27:22 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 04, 2021, 09:02:05 AM
See http://masm32.com/board/index.php?topic=9283.msg101872#msg101872
Title: Re: type of variable
Post by: JK on April 04, 2021, 08:18:40 PM
@nidud,

thanks, exactly what i need. "TYPEID" is ASMC specific i suppose ...


@jj,

thanks a lot, i finally got it! If i use "TYPE" like this:
var_type = TYPE var
then var_type is the same for DWORD, SDWORD and REAL4

but if i use it like this:
  if type(arg) eq DWORD
    echo arg is a    DWORD
  elseif type(arg) eq SDWORD
    echo arg is a    SDWORD
  elseif type(arg) eq REAL4
    echo arg is a    REAL4

then indeed i can keep those types apart - great! With this info i can create something similar to nidud´s TYPEID for ml/ml64 and UASM too.


BTW, where is this behavior documented?

MS´s documentation is lousy (https://docs.microsoft.com/en-us/cpp/assembler/masm/operator-type?view=msvc-160).
The funniest thing about it is this text at the bottom of the page
QuoteIs this page helpful?
Do they really ask this after presenting ... ehm - nothing?


Thanks again to both of you
JK
Title: Re: type of variable
Post by: jj2007 on April 04, 2021, 08:43:01 PM
Quote from: JK on April 04, 2021, 08:18:40 PMBTW, where is this behavior documented?

Nowhere afaik - I found it by trial and error. It's needed for Str$(any number) (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1186) :cool:
Title: Re: type of variable
Post by: nidud on April 05, 2021, 12:03:56 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 01:49:05 AM
Quote from: nidud on April 05, 2021, 12:03:56 AM
Quote from: JK on April 04, 2021, 08:18:40 PMBTW, where is this behavior documented?

The EQ operator (https://github.com/nidud/asmc/blob/master/doc/operator/eq.md) compare type, size, and offset.

a dd 1.0
b dd 2.0

    %echo @CatStr(%(a eq a))
    %echo @CatStr(%(a[4] eq b))
    %echo @CatStr(%(a eq b))
    %echo @CatStr(%(typeof(a) eq typeof(b)))


Error A2102: Symbol not defined : typeof
Title: Re: type of variable
Post by: nidud on April 05, 2021, 04:01:09 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 05:09:57 AM
Did you read what the post was all about? You are only demonstrating that MASM and AsmC are no longer compatible, thanks to your weird decision to abolish the MASM keyword type...
Title: Re: type of variable
Post by: nidud on April 05, 2021, 07:03:24 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 07:47:13 AM
Your example is entirely useless. This is what we were discussing:

include \masm32\include\masm32rt.inc

.data
a dd 1
b REAL4 2.0

%echo @CatStr(%typeof(a))
%echo @CatStr(%typeof(b))

.code
start:
  exit
end start


Output: 2x4, which is not helpful when deciding if, for example, fld or fild should be used for these variables. What we were discussing is this sequence, which works like a charm but is not documented:
if type(a) eq DWORD
echo a is a DWORD
elseif type(a) eq REAL4
echo a is a REAL4
else
echo error
endif

if type(b) eq DWORD
echo b is a DWORD
elseif type(b) eq REAL4
echo b is a REAL4
else
echo error
endif


Output:
a is a DWORD
b is a REAL4


I hope you get it now.

Quote from: nidud on April 05, 2021, 07:03:24 AMIf that was true then you wouldn't be consistently lying.

When you have no more arguments, you throw insults. You are a troll.
Title: Re: type of variable
Post by: LiaoMi on April 05, 2021, 08:41:06 AM
Microsoft Corporation - Microsoft Macro Assembler 6.11 Reference Manual_Programmers Guide-Microsoft Corporation (1992)

Testing for Argument Type and Environment
Macros can expand conditional blocks of code by testing for argument type with the
OPATTR operator. OPATTR returns a single word constant that indicates the
type and scope of an expression, like this:

OPATTR expression

If expression is not valid or is forward-referenced, OPATTR returns a 0.
Otherwise, the return value incorporates the bit flags shown in the table below.

OPATTR serves as an enhanced version of the .TYPE operator, which returns
only the low byte (bits 0 – 7) shown in the table. Bits 11 – 15 of the return value are
undefined.
Bit Set If expression
0 References a code label
1 Is a memory variable or has a relocatable data label
2 Is an immediate value
3 Uses direct memory addressing
4 Is a register value
5 References no undefined symbols and is without error
6 Is relative to SS
7 References an external label
8–10 Has the following language type:
◆ 000 — No language type
◆ 001 — C
◆ 010 —SYSCALL
◆ 011 —STDCALL
◆ 100 — Pascal
◆ 101 — FORTRAN
◆ 110 — Basic
A macro can use OPATTR to determine if an argument is a constant, a register, or
a memory operand. With this information, the macro can conditionally generate the
most efficient code depending on argument type.
For example, given a constant argument, a macro can test it for 0. Depending on the
argument's value, the code can select the most effective method to load the value
into a register:

IF CONST
mov bx, CONST ; If CONST > 0, move into BX
ELSE
sub bx, bx ; More efficient if CONST = 0
ENDIF


The second method is faster than the first, yet has the same result (with the
byproduct of changing the processor flags).
The following macro illustrates some techniques using OPATTR by loading an
address into a specified offset register:

load MACRO reg:REQ, adr:REQ
IF (OPATTR (adr)) AND 00010000y ;; Register
IFDIFI reg, adr ;; Don't load register
mov reg, adr ;; onto itself
ENDIF
ELSEIF (OPATTR (adr)) AND 00000100y
mov reg, adr ;; Constant
ELSEIF (TYPE (adr) EQ BYTE) OR (TYPE (adr) EQ SBYTE)
mov reg, OFFSET adr ;; Bytes
ELSEIF (SIZE (TYPE (adr)) EQ 2
mov reg, adr ;; Near pointer
ELSEIF (SIZE (TYPE (adr)) EQ 4
mov reg, WORD PTR adr[0] ;; Far pointer
mov ds, WORD PTR adr[2]
ELSE
.ERR <Illegal argument>
ENDIF
ENDM


TYPE with Forward References

MASM 5.1 evaluates .TYPE on both assembly passes. This means it yields zero on
the first pass and nonzero on the second pass, if applied to an expression that
forward-references a symbol.
MASM 6.1 evaluates .TYPE only on the first assembly pass. As a result, if the
operand references a symbol that has not yet been defined, .TYPE yields a value of
zero. This means that .TYPE, if used in a conditional-assembly construction, may
yield different results in MASM 6.1 than in MASM 5.1.

Comparing Types Using EQ and NE with OPTION M510
With OPTION M510, the assembler converts types to a constant value before
comparisons with EQ and NE. Code types are converted to values of 0FFFFh
(near) or 0FFFEh (far). If OPTION M510 is not enabled, the assembler converts
types to constants only when comparing them with constants. Thus, MASM 6.1
recognizes only equivalent qualified types as equal expressions.

For existing MASM 5.1 code, these distinctions affect only the use of the TYPE
operator in conjunction with EQ and NE. The following example illustrates how
the assembler compares types with and without compatibility mode:
MYSTRUCT STRUC
f1 DB 0
f2 DB 0
MYSTRUCT ENDS
; With OPTION M510
val = (TYPE MYSTRUCT) EQ WORD ; True: 2 EQ 2
val = 2 EQ WORD ; True: 2 EQ 2
val = WORD EQ WORD ; True: 2 EQ 2
val = SWORD EQ WORD ; True: 2 EQ 2
; Without OPTION M510
val = (TYPE MYSTRUCT) EQ WORD ; False: MyStruct NE WORD
val = 2 EQ WORD ; True: 2 EQ 2
val = WORD EQ WORD ; True: WORD EQ WORD
val = SWORD EQ WORD ; False: SWORD NE WORD


Use of Constant and PTR as a Type with OPTION M510
You can use a constant as the left operand to PTR in compatibility mode.
Otherwise, you must use a type expression. With OPTION M510, a constant must
have a value of 1 (BYTE), 2 (WORD), 4 (DWORD), 6 (FWORD), 8
(QWORD) or 10 (TBYTE). The assembler treats the constant as the
parenthesized type. Note that the TYPE operator yields a type expression, but the
SIZE operator yields a constant.
; With OPTION M510
MyData DW 0
mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
mov (SIZE MyData) PTR [bx], 10 ; Legal
mov 2 ptr [bx], 10 ; Legal
; Without OPTION M510
MyData WORD 0
mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
; mov (SIZE MyData) PTR [bx], 10 ; Illegal
; mov 2 PTR [bx], 10 ; Illegal
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 08:55:30 AM
@LiaoMi: Can you highlight (e.g. in red) the sentence that explains why this works?
if type(a) eq DWORD
echo a is a DWORD
elseif type(a) eq REAL4
echo a is a REAL4
else
echo error
endif

if type(b) eq DWORD
echo b is a DWORD
elseif type(b) eq REAL4
echo b is a REAL4
else
echo error
endif
Title: Re: type of variable
Post by: nidud on April 05, 2021, 09:36:58 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 09:39:01 AM
You are drunk, nidud :tongue:
Title: Re: type of variable
Post by: nidud on April 05, 2021, 09:55:18 AM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 09:58:58 AM
Yep, you are right, the language is absolutely awful and cryptic but it could indeed be interpreted that way. And it appears in a document that is 20 years old and no longer available at Microsoft docs, but ok it is "documented" somewhere.

So finally you did something useful tonight, congrats :thumbsup:
Title: Re: type of variable
Post by: LiaoMi on April 05, 2021, 07:22:20 PM
Hi jj2007,

Operators
Operators are used in expressions. The value of the expression is determined at
assembly time and does not change when the program runs.
Operators should not be confused with processor instructions. The reserved
word ADD is an instruction; the plus sign (+) is an operator. For example,
Amount+2 illustrates a valid use of the plus operator (+). It tells the assembler to
add 2 to the constant value Amount, which might be a value or an address. Contrast
this operation, which occurs at assembly time, with the processor's ADD
instruction. ADD tells the processor at run time to add two numbers and store the
result.

The assembler evaluates expressions that contain more than one operator according
to the following rules:
◆ Operations in parentheses are performed before adjacent operations.
◆ Binary operations of highest precedence are performed first.
◆ Operations of equal precedence are performed from left to right.
◆ Unary operations of equal precedence are performed right to left.
Table 1.3 lists the order of precedence for all operators. Operators on the same line
have equal precedence.

Table 1.3 Operator Precedence
Precedence Operators
1 ( ), [ ]
2 LENGTH, SIZE, WIDTH, MASK, LENGTHOF, SIZEOF
3 . (structure-field-name operator)
4 : (segment-override operator), PTR
5 LROFFSET, OFFSET, SEG, THIS, TYPE
6 HIGH, HIGHWORD, LOW, LOWWORD
7 + ,– (unary)
8 *, /, MOD, SHL, SHR
9 +, – (binary)
10 EQ, NE, LT, LE, GT, GE
11 NOT
12 AND
13 OR, XOR
14 OPATTR, SHORT, .TYPE

In general, the entire document describes the use of types and their meaning. You can get an owned type in almost any case, from any record. I have not tested whether this is the case, but here is one example.

LENGTHOF, SIZEOF, and TYPE for Arrays
When applied to arrays, the LENGTHOF, SIZEOF, and TYPE operators return
information about the length and size of the array and about the type of the
initializers.
The LENGTHOF operator returns the number of elements in the array. The
SIZEOF operator returns the number of bytes used by the initializers in the array
definition. TYPE returns the size of the elements of the array. The following
examples illustrate these operators:

array WORD 40 DUP (5)
larray EQU LENGTHOF array ; 40 elements
sarray EQU SIZEOF array ; 80 bytes
tarray EQU TYPE array ; 2 bytes per element

num DWORD 4, 5, 6, 7, 8, 9, 10, 11
lnum EQU LENGTHOF num ; 8 elements
snum EQU SIZEOF num ; 32 bytes
tnum EQU TYPE num ; 4 bytes per element

warray WORD 40 DUP (40 DUP (5))
len EQU LENGTHOF warray ; 1600 elements
siz EQU SIZEOF warray ; 3200 bytes
typ EQU TYPE warray ; 2 bytes per element


LENGTHOF, SIZEOF, and TYPE for Strings
Because strings are simply arrays of byte elements, the LENGTHOF, SIZEOF,
and TYPE operators behave as you would expect, as illustrated in this example:

msg BYTE "This string extends ",
"over three ",
"lines."
lmsg EQU LENGTHOF msg ; 37 elements
smsg EQU SIZEOF msg ; 37 bytes
tmsg EQU TYPE msg ; 1 byte per element


LENGTHOF, SIZEOF, and TYPE for Structures
The size of a structure determined by SIZEOF is the offset of the last field, plus the
size of the last field, plus any padding required for proper alignment. (For
information about alignment, see "Declaring Structure and Union Types," earlier in
this chapter.)

This example, using the preceding data declarations, shows how to use the
LENGTHOF, SIZEOF, and TYPE operators with structures.

INFO STRUCT
buffer BYTE 100 DUP (?)
crlf BYTE 13, 10
query BYTE 'Filename: '
endmark BYTE 36
drives DISKDRIVES <0, 1, 1>
INFO ENDS

info1 INFO { , , 'Dir' }
lotsof INFO { , , 'file1', , {0,0,0} },
{ , , 'file2', , {0,0,1} },
{ , , 'file3', , {0,0,2} }

sinfo1 EQU SIZEOF info1 ; 116 = number of bytes in
; initializers
linfo1 EQU LENGTHOF info1 ; 1 = number of items
tinfo1 EQU TYPE info1 ; 116 = same as size

slotsof EQU SIZEOF lotsof ; 116 * 3 = number of bytes in
; initializers
llotsof EQU LENGTHOF lotsof ; 3 = number of items
tlotsof EQU TYPE lotsof ; 116 = same as size for structure
; of type INFO


LENGTHOF, SIZEOF, and TYPE for Unions
The size of a union determined by SIZEOF is the size of the longest field plus any
padding required. The length of a union variable determined by LENGTHOF
equals the number of initializers defined inside angle brackets or curly braces.
TYPE returns a value indicating the type of the longest field.
DWB UNION
d DWORD ?
w WORD ?
b BYTE ?
DWB ENDS

num DWB {0FFFFh}
array DWB (100 / SIZEOF DWB) DUP ({0})

snum EQU SIZEOF num ; = 4
lnum EQU LENGTHOF num ; = 1
tnum EQU TYPE num ; = 4

sarray EQU SIZEOF array ; = 100 (4*25)
larray EQU LENGTHOF array ; = 25
tarray EQU TYPE array ; = 4


LENGTHOF, SIZEOF, and TYPE with Records
The SIZEOF and TYPE operators applied to a record name return the number of
bytes used by the record. SIZEOF returns the number of bytes a record variable
occupies. You cannot use LENGTHOF with a record declaration, but you can use
it with defined record variables. LENGTHOF returns the number of records in an
array of records, or 1 for a single record variable. The following example illustrates
these points.
; Record definition
; 9 bits stored in 2 bytes
RGBCOLOR RECORD red:3, green:3, blue:3

mov ax, RGBCOLOR ; Equivalent to "mov ax, 01FFh"
; mov ax, LENGTHOF RGBCOLOR ; Illegal since LENGTHOF can
; apply only to data label
mov ax, SIZEOF RGBCOLOR ; Equivalent to "mov ax, 2"
mov ax, TYPE RGBCOLOR ; Equivalent to "mov ax, 2"

; Record instance
; 8 bits stored in 1 byte
RGBCOLOR2 RECORD red:3, green:3, blue:2
rgb RGBCOLOR2 <1, 1, 1> ; Initialize to 00100101y

mov ax, RGBCOLOR2 ; Equivalent to
; "mov ax, 00FFh"
mov ax, LENGTHOF rgb ; Equivalent to "mov ax, 1"
mov ax, SIZEOF rgb ; Equivalent to "mov ax, 1"
mov ax, TYPE rgb ; Equivalent to "mov ax, 1"
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 07:42:51 PM
Hi LiaoMi,

I just checked the MasmBasic library source: TYPE appears 198 times, opattr a bit more often. No need to explain to me what they do. The real issue is with the cryptic phrase that [censured] nidud found in an obscure old document:

MASM 6.1 recognizes only equivalent qualified types as equal expressions

Normally...
if x eq y
  echo x is the same as y
endif

... means that x and y are constants that have the same numeric value. The exception to this rule is indeed this:

if type(a) eq DWORD
echo a is a DWORD
elseif type(a) eq REAL4
echo a is a REAL4
endif


if a is a DWORD, it's type is 4 (i.e. the numeric value of its type is 4)
if a is a REAL4, it's type is 4

So in both cases we should expect "a is a DWORD".

And yet, Masm and its clones distinguish them from each other: MASM 6.1 recognizes only equivalent qualified types as equal expressions. Which means that under the hood the numeric value 4 (DWORD or REAL4) has a second string property, and that the assembler knows somehow that "EQ" is the wrong operator for this. So instead, it uses (internally)

ifidn type(a), <DWORD>
echo a is a DWORD
elseifidn type(a), <REAL4>
echo a is a REAL4
endif


That is clever, and necessary for many of my macros, but afaik it has not been documented by Micros*t in the last 28 years or so (try a google phrase search for "equivalent qualified types"). MASM 6.1 was released in January 1993 (http://bytepointer.com/masm/index.htm#MASM_6.1)...

[Admin]
We don't say naughty things about other members.  :skrewy:
Title: Re: type of variable
Post by: JK on April 05, 2021, 09:31:43 PM
Thanks a lot, i am more than happy with all the answers i got, i learned a lot in this thread (... and please stop arguing  :eusa_pray:)!


As i see it now, TYPE seems to be kind of a Cameleon, internally it holds more information than is returned by this form:
t = TYPE var
t gets only information about the the size of an element, where, as LiaoMi showed, there are differences between, "SIZEOF", "LENGHTOF" and "TYPE"

wheras used in this form
if type(arg) eq DWORD
    echo arg is a    DWORD
  elseif type(arg) eq SDWORD
    echo arg is a    SDWORD
  elseif type(arg) eq REAL4
    echo arg is a    REAL4

the whole information of "TYPE(xx)" (in contrast to the return value) is compared by "EQ". This might be a feature of the compare operator "EQ", or of the usage as "expression" (TYPE(xxx)) or a result of a combination of both.


Bottomline: it might be interesting to know, why it works, but much more important (to me) is to know, that it works, because this is the key to a range of possibilities, i didn´t have before.


JK
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 09:34:05 PM
Quote from: jj2007 on April 05, 2021, 07:42:51 PM
[Admin]
We don't say naughty things about other members.  :skrewy:

I fully agree :thumbsup:

Quote from: nidud on April 05, 2021, 07:03:24 AMIf that was true then you wouldn't be consistently lying.
Title: Re: type of variable
Post by: nidud on April 05, 2021, 10:00:36 PM
deleted
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 10:52:08 PM
It seems really difficult to understand, so I wrote a detailed example - source attached, plain Masm32.

Bottom line is that under the hood the numeric value 4 (type(DWORD) or type(REAL4)) has a second string property.

The type of MyDW is TYPE(MyDW) (useless)
The type of MyR4 is TYPE(MyR4) (useless)
The type of MyDW is 4 (correct but not very useful)
The type of MyR4 is 4 (correct but not very useful)

---- type(x) eq REAL4/DWORD (undocumented but best option) ----
MyDW is NOT a REAL4 (correct)
MyR4 is NOT a DWORD (correct)

---- type(x) eq 4 ----
MyDW is a REAL4 (NOT correct)
MyR4 is a DWORD (NOT correct)
MyDW is a REAL4 (NOT correct)
MyR4 is a DWORD (NOT correct)

---- using ifidn, i.e. string comparison  ----
MyDW is NOT a REAL4 (correct)
MyDW is NOT a DWORD (correct)
Title: Re: type of variable
Post by: HSE on April 05, 2021, 11:00:56 PM
 :biggrin:  TypeConfusion is NOT valid
Title: Re: type of variable
Post by: hutch-- on April 05, 2021, 11:08:10 PM
This is all I have ever needed in both 32 and 64 bit MASM.

  ; -------------------------
  ; determine an operand type
  ; -------------------------
    op_type MACRO arg:REQ
      LOCAL result
      result = opattr(arg)
        IF result eq 37         ;; label, either local or global
          EXITM %1
        ELSEIF result eq 42     ;; GLOBAL var
          EXITM %2
        ELSEIF result eq 98     ;; LOCAL  var
          EXITM %3
        ELSEIF result eq 36     ;; immediate operand or constant
          EXITM %4
        ELSEIF result eq 48     ;; register
          EXITM %5
        ELSEIF result eq 805    ;; local procedure in code
          EXITM %6
        ELSEIF result eq 933    ;; external procedure or API call
          EXITM %7
        ENDIF
      EXITM %0                  ;; anything else
    ENDM


I have also got argsize and regsize.
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 11:17:38 PM
Quote from: hutch-- on April 05, 2021, 11:08:10 PM
This is all I have ever needed in both 32 and 64 bit MASM.

Yes, that works fine, and it's ok to distinguish between immediates, registers and global or local variables. Indeed, when I type opa<space> in my editor, it inserts oa = (opattr arg) AND 127, to which I usually add something like
if oa eq atImmediate
...
elseif oa eq atRegister
...
endif


However, opattr tells you "it's a local variable" but it does not tell you whether it's a DWORD, a REAL4 or a QWORD. That's where type kicks in as
if type(myvar) eq DWORD
  fild myvar
elseif type(myvar) eq REAL4
  fld myvar
elseif type(myvar) eq QWORD
  fild myvar
endif
Title: Re: type of variable
Post by: hutch-- on April 05, 2021, 11:41:41 PM
I mentioned that I have both data and register sizes working.
Title: Re: type of variable
Post by: jj2007 on April 05, 2021, 11:46:32 PM
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) (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1186) does the three steps silently under the hood.
Title: Re: type of variable
Post by: TouEnMasm on April 06, 2021, 07:24:57 AM

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


Title: Re: type of variable
Post by: jj2007 on April 06, 2021, 08:17:53 AM
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
Title: Re: type of variable
Post by: TouEnMasm on April 06, 2021, 11:19:55 PM

The Macro is the principle.
It can be see in action here http://masm32.com/board/index.php?topic=8885.msg97287#msg97287 (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
Title: Re: type of variable
Post by: jj2007 on April 13, 2021, 12:18:55 PM
Windows Data Types (https://docs.microsoft.com/en-us/windows/win32/winprog/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
Title: Re: type of variable
Post by: TimoVJL on April 13, 2021, 02:57:21 PM
Quote from: jj2007 on April 13, 2021, 12:18:55 PM
Windows Data Types (https://docs.microsoft.com/en-us/windows/win32/winprog/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 ?
Title: Re: type of variable
Post by: 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 (https://docs.microsoft.com/en-us/windows/win32/winprog/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;
Title: Re: type of variable
Post by: LiaoMi on April 13, 2021, 08:47:57 PM
Quote from: jj2007 on April 13, 2021, 12:18:55 PM
Windows Data Types (https://docs.microsoft.com/en-us/windows/win32/winprog/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.
Title: Re: type of variable
Post by: 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
Title: Re: type of variable
Post by: LiaoMi on April 13, 2021, 08:57:52 PM
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:
(https://www.codeproject.com/KB/Articles/1080585/mFig6.jpg)

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:
(https://www.codeproject.com/KB/Articles/1080585/mFig7.jpg)

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:
(https://www.codeproject.com/KB/Articles/1080585/mFig8.jpg)

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.
(https://www.codeproject.com/KB/Articles/1080585/mFig9.jpg)

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
Title: Re: type of variable
Post by: jj2007 on April 13, 2021, 09:03:26 PM
That's all correct, and that's why deb (http://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1019) 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...
Title: Re: type of variable
Post by: LiaoMi on April 13, 2021, 09:38:49 PM
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:
Title: Re: type of variable
Post by: jj2007 on April 13, 2021, 09:44:55 PM
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.
Title: Re: type of variable
Post by: LiaoMi on April 13, 2021, 10:28:14 PM
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.
Title: Re: type of variable
Post by: LiaoMi on April 13, 2021, 10:38:08 PM
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 (https://docs.microsoft.com/en-us/windows/win32/winprog/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:
Title: Re: type of variable
Post by: Vortex on April 13, 2021, 11:06:08 PM
QuoteI 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:

I agree with Jochen. Why so much noise about type checking? An assembler is not a compiler
Title: Re: type of variable
Post by: jj2007 on April 13, 2021, 11:37:00 PM
Quote from: Vortex on April 13, 2021, 11:06:08 PM
QuoteI 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:

I agree with Jochen. Why so much noise about type checking? An assembler is not a compiler

Erol,

The type checking madness is not limited to Assembler. Attached a very simple standard Windows source written in FreeBasic (which passes it to Gcc).

Here are the warnings for 100 lines of code:
TmpFb.bas(14) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(20) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(25) warning 3(1): Passing different pointer types, at parameter 2 of SETWINDOWTEXT()
TmpFb.bas(27) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(29) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(32) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGEA()
TmpFb.bas(38) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGE()
TmpFb.bas(77) warning 1(1): Passing scalar as pointer, at parameter 2 of LOADICON()
TmpFb.bas(80) warning 4(1): Suspicious pointer assignment
TmpFb.bas(85) warning 4(1): Suspicious pointer assignment
TmpFb.bas(90) warning 4(1): Suspicious pointer assignment
TmpFb.bas(14) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(20) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(25) warning 3(1): Passing different pointer types, at parameter 2 of SETWINDOWTEXT()
TmpFb.bas(27) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(29) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(32) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGEA()
TmpFb.bas(38) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGE()
TmpFb.bas(77) warning 1(1): Passing scalar as pointer, at parameter 2 of LOADICON()
TmpFb.bas(80) warning 4(1): Suspicious pointer assignment
TmpFb.bas(85) warning 4(1): Suspicious pointer assignment
TmpFb.bas(90) warning 4(1): Suspicious pointer assignment


So 22% of the source cause an absolutely useless warning. No wonder that much of the "professional" software installed on our machines is so bloated and buggy. No sane person can keep control over a source that either issues crappy warnings for over 20% of its lines, or requires you to override the wonderful brilliant type checking feature with type casts in order to avoid the warnings. This is madness, fullstop.
Title: Re: type of variable
Post by: hutch-- on April 14, 2021, 12:38:25 AM
 :biggrin:

He he, now you get why I am a data SIZE man, the whole idea of masking data sizes with data types is an act of stupidity. x86-64 processors at their base level work on the data SIZE, not phony types.
Title: Re: type of variable
Post by: HSE on April 14, 2021, 06:46:20 AM
Hi Hutch!

I hope you enjoy your coffee... and take things easy  :biggrin: :biggrin: :biggrin:






Ready?





You can remove a lot of your loved SIZE thing and reduce around 260 lines!

A very reduced REGISTER macro pass examples64 test:
;; *************************************************************************************************
;; -----------------------------
;; Process the first 4 registers
;; -----------------------------
    REGISTER MACRO anum,breg,wreg,dreg,qreg,xreg
      LOCAL elbl, gelbl

      ssize SIZESTR <anum>

    ;; ++++++++++++++++++++++
    ;; text avaluations first
    ;; ++++++++++++++++++++++
      IF ssize GT 4                             ;; handle ADDR notation
        lead SUBSTR <anum>,1,4
        IFIDNI lead,<ADDR>
          wrd2 SUBSTR <anum>,6
          lea qreg, wrd2
          goto elbl
        ENDIF
      ENDIF

      IF ssize GT 1                             ;; handle quoted text
        lead SUBSTR <anum>,1,1
        IFIDNI lead,<">
          mov qreg, reparg(anum)
          goto elbl
        ENDIF
      ENDIF

    ;; ++++++++++++++++++++++++++
    ;; data type evaluations next
    ;; ++++++++++++++++++++++++++

      IF getattr(anum) EQ IMM                           ;; IMMEDIATE
        mov qreg, anum
        goto elbl
      ENDIF

      IF getattr(anum) EQ REG                           ;; REGISTER
        sreg = regsize(anum)
        IF sreg EQ 0
          .err
        ELSEIF sreg EQ 1
          IFIDNI <breg>,<anum>
            and qreg, 0FFh
          ELSE
            xor qreg, qreg
            mov breg, anum
          ENDIF
          goto elbl
        ELSEIF sreg EQ 2
          IFIDNI <wreg>,<anum>
            and qreg, 0FFFFh
          ELSE
            xor qreg, qreg
            mov wreg, anum
          ENDIF
          goto elbl
        ELSEIF sreg EQ 4
          IFIDNI <dreg>,<anum>
            and qreg, 0FFFFFFh
          ELSE
            xor qreg, qreg
            mov dreg, anum
          ENDIF
          goto elbl
        ELSEIF sreg EQ 8
          IFIDNI <qreg>,<anum>
          ELSE
            mov qreg, anum
          ENDIF
          goto elbl
        ENDIF
      ENDIF
     
      if type(anum) eq BYTE
          xor qreg, qreg
          mov breg, anum
      elseif type(anum) eq SBYTE
          movsx qreg, anum
      elseif type(anum) eq WORD
          xor qreg, qreg
          mov wreg, anum
      elseif type(anum) eq SWORD
          movsx qreg, anum
      elseif type(anum) eq DWORD
          xor qreg, qreg
          mov dreg, anum
      elseif type(anum) eq SDWORD
          movsxd qreg, anum
      elseif type(anum) eq QWORD
          mov qreg, anum
      elseif type(anum) eq SQWORD
          mov qreg, anum
      elseif type(anum) eq REAL4
          mov qreg, anum
          movss xreg, DWORD PTR anum
      elseif type(anum) eq REAL8
          mov qreg, anum
          movsd xreg, anum
      else
          goto gelbl
      endif
      goto elbl
       
    :gelbl
   
    ;; +++++++++++++++++++++++
    ;; Unknown data type error
    ;; +++++++++++++++++++++++
      % echo     ***************************
      % echo     ERROR Unknown argument type -> anum        ;; ERROR UNKNOWN DATA TYPE
      % echo     ***************************
      .err

    :elbl
    ENDM




Similar thing in STACKARGS macro:
;; *************************************************************************************************
;; -------------------------------------------------------------
;; Process all following stack arguments without limit.
;; -------------------------------------------------------------
    STACKARG MACRO anum,disp
      LOCAL elbl, gelbl

      ssize SIZESTR <anum>

    ;; ++++++++++++++++++++++
    ;; text avaluations first
    ;; ++++++++++++++++++++++
      IF ssize GT 4                             ;; handle ADDR notation
        lead SUBSTR <anum>,1,4
        IFIDNI lead,<ADDR>
          wrd2 SUBSTR <anum>,6
          lea rax, wrd2
          mov QWORD PTR [rsp+disp], rax
          goto elbl
        ENDIF
      ENDIF

      IF ssize GT 1                             ;; handle quoted text
        lead SUBSTR <anum>,1,1
        IFIDNI lead,<">
          mov rax, reparg(anum)
          mov QWORD PTR [rsp+disp], rax
          goto elbl
        ENDIF
      ENDIF

    ;; ++++++++++++++++++++++++++
    ;; data type evaluations next
    ;; ++++++++++++++++++++++++++
      IF getattr(anum) EQ IMM                           ;; IMMEDIATE
        mov QWORD PTR [rsp+disp], anum
        goto elbl
      ENDIF

      IF getattr(anum) EQ REG                           ;; REGISTER
        sreg = regsize(anum)
        IF sreg EQ 0
          .err
        ENDIF
        IF sreg EQ 1
          mov BYTE PTR [rsp+disp], anum
          goto elbl
        ENDIF
        IF sreg EQ 2
          mov WORD PTR [rsp+disp], anum
          goto elbl
        ENDIF
        IF sreg EQ 4
          mov DWORD PTR [rsp+disp], anum
          goto elbl
        ENDIF
        IF sreg EQ 8
          mov QWORD PTR [rsp+disp], anum
          goto elbl
        ENDIF
      ENDIF

    xor rax,rax
     if type(anum) eq BYTE
          mov al, anum
     elseif type(anum) eq SBYTE
          movsx rax, anum
     elseif type(anum) eq WORD
          mov ax, anum
     elseif type(anum) eq SWORD
          movsx rax, anum
     elseif (type(anum) eq DWORD) or (type(anum) eq REAL4)
          mov eax, anum
     elseif type(anum) eq SDWORD
          movsxd rax, anum
     elseif (type(anum) eq QWORD) or (type(anum) eq SQWORD) or (type(anum) eq REAL8)
         mov rax, anum
     else
         goto gelbl
      endif
      mov QWORD PTR [rsp+disp], rax

      goto elbl

    :gelbl
   
    ;; +++++++++++++++++++++++
    ;; Unknown data type error
    ;; +++++++++++++++++++++++
      % echo     ***************************
      % echo     ERROR Unknown argument type -> anum        ;; ERROR UNKNOWN DATA TYPE
      % echo     ***************************
      .err

    :elbl
    ENDM



This also satisfy Unprototyped and Vararg functions in ABI.

Of course, a lot more tests are needed.

Regards, HSE.
Title: Re: type of variable
Post by: hutch-- on April 14, 2021, 07:16:00 AM
Hector,

You will have to forgive me here but I place already tested reliability over any changes. To revise the macros that are already up and tested means having to set it all up again and perform exhaustive tests again and at the moment I have too many other things on my plate.

The videos are a lot of work but I am getting faster at them with practice. Making extra library modules comes next and writing the test code for each module is reasonably time consuming. Then there is matching example code that has to be intelligible as well.

At least some of your suggestions look very useful and I will try and get to them but anything I add or change has to be rigorously tested so that none of the existing capacity gets trashed.

Title: Re: type of variable
Post by: HSE on April 14, 2021, 07:54:45 AM
Yes Hutch, no explanation needed.  :thumbsup:

Quote from: hutch-- on April 14, 2021, 07:16:00 AM
but anything I add or change has to be rigorously tested so that none of the existing capacity gets trashed.
That is. Just building libraries I found a little mistake with floating points  :biggrin: (corrected in previous post).
For sure something more can fail!
Title: Re: type of variable
Post by: jj2007 on April 14, 2021, 10:53:10 PM
Quote from: hutch-- on April 14, 2021, 07:16:00 AMrigorously tested

A propos - extracted from the Gcc headers:
#define WM_MOUSELAST                    0x0209
#define WM_MOUSELAST                    0x020A
#define WM_MOUSELAST                    0x020D
#define WM_MOUSELAST                    0x020E

:tongue:
Title: Re: type of variable
Post by: Vortex on April 14, 2021, 11:12:26 PM
Hi Jochen,

I agree with your comments. It's just a lot of paint to type all those useless type castings.
Title: Re: type of variable
Post by: jj2007 on April 14, 2021, 11:15:50 PM
Quote from: Vortex on April 14, 2021, 11:12:26 PMIt's just a lot of paint to type all those useless type castings.

Hi Erol,

"For your own safety, it's strictly forbidden to use xxx - but don't worry, I'll show you an easy workaround" :badgrin:
Title: Re: type of variable
Post by: hutch-- on April 15, 2021, 12:55:57 AM
This is what I have in the main 64 bit include file.

WM_MOUSEFIRST                        equ 200h
WM_MOUSELAST                         equ 209h

Title: Re: type of variable
Post by: nidud on April 15, 2021, 01:01:10 AM
deleted
Title: Re: type of variable
Post by: jj2007 on May 03, 2021, 09:15:01 AM
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 (https://docs.microsoft.com/en-us/windows/win32/winprog/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;

Now I counted a few more (1000+), see attachment :cool:
Title: Re: type of variable
Post by: hutch-- on May 03, 2021, 09:51:03 AM
I have a view on type checking, argument count checking, never ending equates with different names, read the DOCUMENTATION !!!!

Add a maze of confusion and you end up with confusion. Even if you get some form of squarking about something that does not match, you still have to look up the documentation to correct the error. Now if you bother to look up the documentation and it shows an argument as being a POINTER, size and arg count will not help you here, you need to know that it is a pointer which will be either 4 or 8 bytes depending on if your code is 32 or 64 bit.

This where you get a TYPEDEF or a #define that is named as a POINTER. Overlaying C/C++ technology on an assembler is getting the cart to pull the horse. When Microsoft release a 64 bit assembler, they are not trying to outpace their C compiler which does all of the things that a C compiler should, it does not do anything that tries to over ride the C compiler.

Now if you want to use an API like SendMessage() in an assembler, you look up the documentation for both the API AND the message you want to send. In 32 bit you can use the PUSH / CALL notation, in 64 bit you are better off using the call automation for any working version of "invoke" and set any handles or pointers to either 32 or 64 bit and this is determined by READING the documentation.
Title: Re: type of variable
Post by: jj2007 on May 03, 2021, 04:37:35 PM
Quote from: hutch-- on May 03, 2021, 09:51:03 AMif you want to use an API like SendMessage() in an assembler

Warnings issues by FreeBasic/Gcc, for perfectly valid and suitable arguments in a 100-line GUI template:
TmpFb.bas(15) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(21) warning 2(1): Passing pointer to scalar, at parameter 3 of APPENDMENU()
TmpFb.bas(28) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(30) warning 1(1): Passing scalar as pointer, at parameter 10 of CREATEWINDOWEX()
TmpFb.bas(33) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGEA()
TmpFb.bas(39) warning 2(1): Passing pointer to scalar, at parameter 4 of SENDMESSAGE()
TmpFb.bas(78) warning 1(1): Passing scalar as pointer, at parameter 2 of LOADICON()
TmpFb.bas(81) warning 4(1): Suspicious pointer assignment
TmpFb.bas(86) warning 4(1): Suspicious pointer assignment


You can "heal" the "bad" code by using e.g.
SendMessage(hEdit, WM_SETTEXT, 0, CAST(LPARAM, @file_char(0)))
instead of
SendMessage(hEdit, WM_SETTEXT, 0, @file_char(0))

It's type madness :cool:
Title: Re: type of variable
Post by: hutch-- on May 03, 2021, 07:47:56 PM
You are right, it looks disgusting. I have yet to comprehend the reasoning that confusing and misleading inexperienced programmers achieves anything else than to make them give up on a particular language.  :thdn:
Title: Re: type of variable
Post by: jj2007 on May 03, 2021, 07:52:11 PM
The SendMessage(hEdit, WM_SETTEXT, 0, CAST(LPARAM, @file_char(0))) game essentially means:

1. Lean back and relax, this is a safe high level language, you can't do anything wrong :cool:
2. Oh, and btw, if you are bothered by cryptic warnings, I'll show you a way to bypass the security measures :tongue:
Title: Re: type of variable
Post by: Thomasid14 on July 02, 2021, 02:18:28 PM
Quote from: JK on April 04, 2021, 02:53:55 AM
Thanks, i know "OPATTR", but it cannot solve my problem.

Suppose i have an argument of a procedure and i want to process this argument in a macro. Different types of arguments would require different processing. I would like to tell from the argument alone, what type of argument it is rachat de credit bancaire (https://www.rachat-credit-info.com/). The "TYPE" operator allows only for a limited decision, i cannot distinguish e.g between "DWORD" and "REAL4", because "4" is returned for both.
But only the macro can deal with this kind of problem I think. Anyway, thanks for the info.
Title: Re: type of variable
Post by: jj2007 on July 02, 2021, 05:21:30 PM
> rachat de credit bancaire
> only the macro can deal with this kind of problem

Are the bots getting more intelligent, or do they pay human spammers more nowadays?