include iostream.a or include ucrlib.aThe iostream.a include file exports several symbols. The UCR Standard Library prefaces all "private" names with a dollar sign ("$"). You should not call any routine in this package that begins with this symbol unless otherwise advised. To avoid name conflicts, you should not define any symbols in your programs that begin with a dollar sign ("$"). Note that future versions of the stdlib (that remain compatible with this release) may change "private" names. To remain compatible with future releases, you must not refer to these "private" names within your programs.
Source code appearing in this chapter is current as of Version Two, Release 40. There may be minor changes between this source code and the current release.
For slightly better control of the output data, you should also take a look at printf and printff in the standard output package.
cout operand1, operand2, ...If an operand is an identifier declared within the VAR..ENDVAR using a standard type definition macro (e.g., integer), then COUT will print the value of that variable using its native format. The following lists the possible output formats:
If the COUT operand is an 80x86 register, COUT can't really determine the data type of the corresponding value, so it prints the value of the register using hexadecimal notation (two digits for eight bit registers, four digits for 16-bit registers, and eight digits for 32-bit registers).
If the COUT operand is a constant, COUT will print that constant as an ASCII character. Similarly, if the COUT operand is a string, COUT will print that string literal to the standard output device.
If the COUT operand is a byte, sbyte, word, sword, dword, or sdword variable, COUT will print type(xxxx) where type is the type name (byte, sbyte, word, etc) and xxxx is the hexadecimal representation of that value. Since programmers can store many different types into these types of variables, COUT does not try to interpret the results.
If you supply any other operand type to COUT, MASM will generate an error.
If you create your own types using the DCLTYPE macro, you can provide a macro that will allow COUT to print your data type. For more details, see the DCLTYPE macro in the chapter on declarations (DCLS) and the section on extending CIN and COUT later in this chapter.
cout "Hello world",13,10The following is a more typical use of the COUT statement:
cout "I=",i, " F=",F, " string='",string,"'",nl I=10 F= 1.500000e+00 'Hello There'
CIN supports the input of all stdlib predefined variable types. It calls the following standard input routines for each of these types:
You can extend CIN so that it can read values of types that you define. See the appropriate section later in this chapter.
var integer intval float fpval string str[128] endvar . . . cout "Enter an integer and a floating point value:" cin intval, fpval cout "Enter a line of text:" cin str . . .
Consider the following type declaration:
dcltype LHex, dword ;A 32-bit hexadecimal value LHex LHvar1 LHex LHVar2=0FFFF0000h LHex LHvar3[20], LHVar4[10]=0FFFFh LHex *LHvar5, *LHvar6=LHVar5, *LHVar7[4], *LHVar8[4]=LHVar5Whenever you declare a variable using one of these type macros, the macro emits the appropriate MASM statements to allocate storage for the variable. For simple variables (like LHvar1 above), the type macro emits the directive specified by the second operand to the DCLTYPE macro (dword in this case):
LHvar1 dword ?When you specify an initial value (as for LHVar2, above), the LHex macro substitutes the initial value for the "?" in the operand field of the MASM directive, e.g.,
LHVar2 dword 0FFFF0000hWhen you declare an array by adding a subscript to the name, the LHex macro generates an appropriate "dup" operator in the operand field of the dword directive:
LHVar3 dword 20 dup (?) LHVar4 dword 10 dup (0FFFFh)If you place an asterisk in front of the variable name, the type macro will use the "dword" directive to reserve four bytes of storage for a far pointer (this isn't obvious in this case since the LHex macro emits a dword directive anyway). If you specify an array or an initial value, the type directive emits the appropriate dword operand:
LHvar5 dword ? LHVar6 dword LHVar5 LHVar7 dword 4 dup (?) LHVar8 dword 4 dup (LHVar5)Consider one more example that clearly demonstrates what is happening when you declare a pointer variable:
dcltype SInt, sbyte ;Short integer: -128..+127 SInt si, *sip si sbyte ? sip dword ?Note that from a C++ point of view the standard library probably should have used the "&" symbol rather then "*" to denote a reference (pointer) variable since the CIN and COUT routines automatically dereference pointer variables. However, the "&" symbol is an operator in MASM and it was easier to use the "*" symbol.
In addition to emiting the directives that allocate space for a variable you declare, the type declaration macros also emit a text equate for each symbol you define. The text equate always takes the following form:
$?varname textequ <typename> LHex H1, *H2=H1 H1 dword ? $?H1 textequ <LHex> H2 dword H1 $?H2 textequ <*LHex>If a variable appears in the operand field of the COUT statement, the COUT macro first checks to see if it is a type macro declared variable using the technique described above. If this is the case, then COUT will invoke one of two macros to print the variable's value:
$$PV_typename varname or $$PP_typename varname cout H1, H2 $$PV_LHex H1 $$PP_LHex H2Although the type declaration macro can create the "$?varname" symbol for you, it is not smart enough to write the $$PP_typename and $$PV_typename macros for you. You must write these macros and they must take the following form:
$$PV_typename macro varname <code that prints varname's value> endm $$PP_typename macro varnamePtr <code that fetches the data at address "varnamePtr" and prints it> endmCOUT automatically preserves the values in the EAX, ES, and DI registers. Therefore, you may use these registers within your macros without saving their contents. If you use any other registers, you must preserve their values within the macro if you expect COUT to preserve their values. Consider the LHex data type defined earlier:
$$PV_LHex macro Hex32 mov ax, word ptr Hex32+2 putw mov ax, word ptr Hex32 putw endm $$PP_LHex macro Hex32Ptr les di, dword ptr Hex32Ptr mov ax, es:[di+2] putw mov ax, es:[di] putw endmCIN interfaces with the DCLTYPE macro in a similar manner except you define $GP_typename and $GV_typename macros that read the data from the standard input. The following macros supply the input side of the LHex data type:
$$GV_LHex macro Hex32toRead getlh mov Hex32ToRead, eax endm $$GP_LHex macro Hex32Ptr2Rd getlh les di, Hex32Ptr2Rd mov es:[di], eax endmOnce you define the macros above, CIN and COUT will work properly with the new data type you've created. In addition to the above macros, you should also define a symbol $$typename whose value is the number of bytes required by the object, e.g.,
$$LHex = 4
You can also use the stdlib ENUM statement (see the chapter on declarations) to declare new data types of which COUT and CIN are aware. Consider a statement like the following:
enum colors, <red, green, blue> typedcl colors, byte
enum colors, <red, green, blue$$PV_colors macro color mov al, byte ptr color call PrintColors endm $$PP_colors macro color les di, dword ptr color mov al, es:[di] call PrintColors endm PrintColors proc cmp al, red jne NotRed print "red" ret NotRed: cmp al, green jne NotGreen print "green" ret NotGreen: cmp al, blue jne NotBlue print "blue" ret NotBlue: print "Illegal Color!" ret PrintColors endp $GV_Colors macro Color2Read call GetColor mov byte ptr Color2Read, al endm $GP_Colors macro ColorPtr call GetColor les di, ColorPtr mov es:[di], al endm TstChar macro Chars forc chr, <Chars> getc tolower cmp al, '&chr&' jne BadColor endm endm GetColor proc near getc jc BadColor ;If GETC error. tolower ;Allow upper and lower case. cmp al, "r" je MustBeRed cmp al, "g" je MustBeGreen cmp al, "b" je MustBeBlue ; Illegal character. Cannot be red, green, or blue at this ; point. So if exceptions are enabled, raise an exception. BadColor: GetXEnabled cmp ax, 0 je NoExceptions mov ax, $Conversion Raise ; If exceptions are not enabled, just return with a bogus value. mov ax, -1 stc ret MustBeRed: tstchar ed mov al, red ret MustBeGreen: tstchar reen mov al, green ret MustBeBlue: tstchar lue mov al, blue ret GetColor endp