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
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
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.
Check \Masm32\MasmBasic\MasmBasic.inc for the string elseif type(tmp$) eq
deleted
See http://masm32.com/board/index.php?topic=9283.msg101872#msg101872
@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
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:
deleted
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
deleted
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...
deleted
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.
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
@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
deleted
You are drunk, nidud :tongue:
deleted
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:
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"
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:
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
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.
deleted
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)
:biggrin: TypeConfusion is NOT valid
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.
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
I mentioned that I have both data and register sizes working.
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.
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
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
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
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
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 ?
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;
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, __ptr64https://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.
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
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
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...
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:
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.
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.
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:
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
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.
: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.
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.
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.
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!
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:
Hi Jochen,
I agree with your comments. It's just a lot of paint to type all those useless type castings.
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:
This is what I have in the main 64 bit include file.
WM_MOUSEFIRST equ 200h
WM_MOUSELAST equ 209h
deleted
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:
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.
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:
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:
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:
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.
> 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?