C is a language which does not specify the I/O facilites in the language itself; rather all I/O is performed via library routines. In practice this results in I/O handling which is no less convenient than any other language, with the added possibility of customising the I/O for a specific application. For example it is possible to provide a routine to replace the standard getchar() (which gets one character from the standard input) with a special getchar(). This is particulary useful when writing code which is to run on a special hardware configuration, while maintaining a high level of compatibility with "standard" C I/O.
There is in fact a Standard I/O library (STDIO) which defines a portable set of I/O routines. These are the routines which are normally used by any C application program. These routines, along with other non-I/O library routines, are listed in detail in a subsequent section of the manual.
The libraries supplied with HI-TECH C are highly compatible with the ANSI libraries, as well as the V7 UNIX libraries, both at the Standard I/O level and the UNIX system call level. The Standard I/O library is complete, and conforms in all respects with the UNIX Standard I/O library. The library routines implementing UNIX system call like functions are as close as possible to those system calls, however there are some UNIX system calls that cannot be simulated on other systems, e.g. the link() operation. However the basic low level I/O routines, i.e. open, close, read, write and lseek are identical to the UNIX equivalents. This means that many programs written to run on UNIX, even if they do not use Standard I/O, will run with little modification when compiled with HI-TECH C.
Libraries for Embedded Systems
The cross compilers, designed to produce code for target systems without operating systems, are supplied with libraries implementing a subset of the STDIO functions. Not provided are those functions dealing with files. Included are printf(), scanf() etc. These operate by calling two low level functions putch and getch() which typically send and receive characters via a serial port. Where the compiler is aimed at a single-chip micro with on-board UART this is used. The source code for all these functions is supplied enabling the user to modify it to address a different serial port.
On some operating systems, notably CP/M, files are treated differently according to whether they contain ASCII (i.e. printable) or binary data. MD-DOS also suffers from this problem, not due to any lack in the operating system itself, but rather because of the hangover from CP/M which results in many programs putting a redundant ctrl-Z at the end of files. Unfortunately there is no way to determine which type of data a file contains (except perhaps by the name or type of the file, and this is not reliable). To overcome this difficulty, there is an extra character which may be included in the MODE string to a fopen() call. To open a file for ASCII I/O, the form of the fopen() call is:
fopen("filename.ext", "r") /* for reading */ fopen("filename.ext", "w") /* for writing */
To open a file for binary I/O, the character 'b' may be appended to the
fopen("filename.ext", "rb") fopen("filename.ext", "wb")
The additional character instructs the STDIO library that this file is to be handled in a strict binary fashion. On CP/M or MS-DOS, a file opened in ASCII mode will have the following special character handling performed by the STDIO routines:
- ('\n') converted to carriage return/newline on output.
- ('\r') ignored on input
- interpreted as End-Of-File on input and, for CP/M only, appended when closing the file.
The special actions performed on ASCII files ensure that the file is written in a format compatible with other programs handling text files, while eliminating the requirement for any special handling by the user program - the file appears to the user program as though it were a UNIX-like text file.
None of these special actions are performed on a file opened in binary mode. This is required when handling any kind of binary data, to ensure that spurious bytes are not inserted, and premature EOF's are not seen.
Since the binary mode character is additional to the normal mode character, this usage is quite compatible with UNIX C. When compiled on UNIX, the additional character will be ignored.
A mention here of the term `stream' is appropriate; stream is used in relation to the STDIO library routines to mean the source or sink of bytes (characters) manipulated by those routines. Thus the FILE pointer supplied as an argu- ment to the STDIO routines may be regarded as a handle on the corresponding stream. A stream may be viewed as a featureless sequence of bytes, originating from or being sent to a device or file or even some other indeterminate source. A FILE pointer should not be confused with the 'file descriptors' used with the low-level I/O functions open(), close(), read() and write(). These form an independent group of I/O functions which perform unbuffered reads and writes to files.
Floating Point Library
HI-TECH C supports floating point as part of the language, however the Z80 implementation provides single precision only; double floats are permitted but are no different to floats. In addition, the standard library, LIBC.LIB, does not contain any floating point routines. These have been separated out into another library, LIBF.LIB. This means that if this library is not searched no floating point support routines will be linked in, thus avoiding any size penalty for the floating point support if it is not used. This is particulary important for printf and scanf, and thus LIBF.LIB contains versions of printf and scanf that do support floating point formats.
Thus, if floating point is used, a -LF option should be used AFTER the source and/or object files to the C command. E.g.:
C -V -O x.c y.c z.obj -LF