TL;DR
TYPE
return the size, in bytes, of the "representing" type of a data structure (such an array).
SIZEOF
return the size, in bytes, of a data structure.
LENGTHOF
returns the number of "elements" in a data structure.
Note that these operators can be applied either to types (e.g. BYTE
) or to labels (e.g. TYPE myLabel
).
The result can be different for same data structures (e.g. records).
Precise meaning is given made below.
Note that there is similarly named operator .TYPE
that can be used in macros to return a byte bitfield containing information about an expression (e.g. it names a register).
This is what is presented by the poorly written MASM documentation in the MSDN.
There is a MASM 6.1 reference document here, I don't know how much authoritative it is but all of this answer is based on it.
Primitives
That document lists TYPE
as an operator similar to SIZEOF
The SIZEOF
and TYPE
operators, when applied to a type, return the size of an integer of that type.
The size attribute associated with each data type is:
Data Type Bytes
BYTE, SBYTE 1
WORD, SWORD 2
DWORD, SDWORD 4
FWORD 6
QWORD 8
TBYTE 10
Here the operators are applied to a type, I believe it's possible to apply them to labels associated with primitives, resulting in the same output.
Arrays
For an array the difference between SIZEOF
and TYPE
(and LENGTHOF
) becomes clear:
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
In this case, the operators are used with labels.
Strings
For String, it suffices to recall that Strings are arrays of bytes.
Structures
For Structures, the concept is similar to the arrays': TYPE
is size of the structure while SIZEOF
is the size of the all the structure objects associated with the label (MASM consider a thing like myLabel db 1, 2, 3
as being three bytes associated with myLabel
):
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.
INFO STRUCT
buffer BYTE 100 DUP (?)
crlf BYTE 13, 10
query BYTE 'Filename: '
endmark BYTE 36
drives DISKDRIVES <0, 1, 1>
INFO ENDS
;One struct
info1 INFO { , , 'Dir' }
;Three structs for this label
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
In this case, the operators are used with labels.
Unions
For Unions, something very similar happens:
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
In this case, the operators are used with labels.
Records
Records are bytes, words, or doublewords in which the individual bits or groups of bits are considered fields.
Quoted from the manual, but not formatted as a quote intentionally.
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"
Here there is a little asymmetry when using the operators with labels and with types.
.TYPE
as an operator for macros
This operator is the old version of OPATTR
and returns a byte with the following content:
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
This has a taste of metaprogramming and it is normally used to optimise the code generated with macros.