Memory and utilities (stdlib.h)¶
Include stdlib.h. This header covers dynamic memory,
string-to-number conversion, integer arithmetic helpers, searching and sorting,
process control, and pseudo-random numbers.
Types and Macros¶
| Name | Meaning |
|---|---|
NULL |
Null pointer constant. |
EXIT_SUCCESS |
Successful program termination status. |
EXIT_FAILURE |
Unsuccessful program termination status. |
RAND_MAX |
Maximum value returned by rand. |
ATEXIT_MAX |
Maximum number of functions that can be registered with atexit(). |
div_t |
Quotient and remainder pair returned by div. |
ldiv_t |
Quotient and remainder pair returned by ldiv. |
MB_CUR_MAX |
Maximum bytes in a multibyte character in the current locale. |
Functions¶
| Function | Summary |
|---|---|
_Noreturn void abort( void ) |
Terminate the program abnormally; does not call atexit handlers. |
int abs(int j) |
Absolute value of a signed int. |
int atexit( void (*func)(void) ) |
Register func to be called at normal program termination (LIFO order). Returns 0 on success, nonzero if the ATEXIT_MAX table is full. |
float atof(const char *nptr) |
Convert the leading decimal text in nptr to float. Note: C89 atof normally returns double; dcc has no double type, so this returns float (IEEE 754 single precision). Accepts nan, inf, and infinity spellings. Overflow returns signed infinity; underflow returns signed zero. |
int atoi(const char *nptr) |
Convert the leading decimal text in nptr to int. |
long atol(const char *nptr) |
Convert the leading decimal text in nptr to long. |
int bdos( int fn, int dearg ) |
Call the CP/M BDOS entry point. |
int bdoshl( int fn, int dearg ) |
Call the CP/M BDOS entry point, returning the full HL result. |
int bios( int fn, int dearg ) |
Call the CP/M BIOS jump table directly. |
int bioshl( int fn, int dearg ) |
Call the CP/M BIOS jump table directly, returning the full HL result. |
const void *bsearch(const void *key, const void *base, size_t num, size_t size, int (*compare)(const void *, const void *)) |
Binary-search a sorted array. |
void *calloc( size_t num, size_t size ) |
Allocate and zero num * size bytes from the heap. |
div_t div(int numer, int denom) |
Signed int division returning quotient and remainder. |
int exec( const char *path, const char *cmdtail ) |
Load and run path, replacing this process. cmdtail is copied to 0x81 (e.g. " ARG1 ARG2"); the first two whitespace-delimited args also seed the default FCBs at 0x5C and 0x6C. Returns -1 if the file is not found; does not return on success. |
int execv( const char *path, char **argv ) |
Like exec() but builds the command tail from argv[1..] (argv[0] is the conventional program name and is ignored for CP/M purposes). argv must be a NULL-terminated array of string pointers. |
_Noreturn void exit( int code ) |
Terminate the program after flushing runtime output. |
void free( void *ptr ) |
Release a heap allocation. |
char *getenv(const char *name) |
Search the environment for name; always returns NULL on CP/M 2.2. |
int inp( unsigned port ) |
Read an 8-bit Z80 I/O port. |
long labs(long j) |
Absolute value of a signed long. |
ldiv_t ldiv(long numer, long denom) |
Signed long division returning quotient and remainder. |
void *malloc( size_t size ) |
Allocate size bytes from the heap. |
int mblen(const char *s, size_t n) |
Length of the multibyte character at s, examining at most n bytes. |
size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) |
Convert at most n multibyte characters from s into the wchar_t array pwcs. |
int mbtowc(wchar_t *pwc, const char *s, size_t n) |
Convert the multibyte character at s into *pwc; examine at most n bytes. |
void outp( unsigned port, unsigned val ) |
Write an 8-bit Z80 I/O port. |
void qsort(void *base, size_t num, size_t size, int (*compare)(const void *, const void *)) |
Sort an array in place. |
int rand(void) |
Return the next pseudo-random integer in the range 0 through RAND_MAX. |
void *realloc( void *ptr, size_t size ) |
Resize a heap allocation, preserving contents up to the smaller size. |
void srand(unsigned int seed) |
Seed the pseudo-random number generator. |
float strtod(const char *nptr, char **endptr) |
Convert leading floating-point text in nptr to float; sets *endptr past consumed input. Note: C89 strtod returns double; dcc returns float (no double type). |
long strtol(const char *nptr, char **endptr, int base) |
Convert text in nptr to long using base 2 through 36, or base 0 for auto-detection. |
unsigned long strtoul(const char *nptr, char **endptr, int base) |
Convert text in nptr to unsigned long using base 2 through 36, or base 0 for auto-detection. |
int system(const char *string) |
Execute a shell command; always returns -1 on CP/M 2.2 (no command processor). |
size_t wcstombs(char *s, const wchar_t *pwcs, size_t n) |
Convert at most n wide characters from pwcs into the char array s. |
int wctomb(char *s, wchar_t wc) |
Convert wide character wc into the multibyte sequence at s. |
Runtime model¶
The standard functions in this header are runtime-backed. DCC C Compiler also declares a
small set of CP/M and Z80 extensions here (bdos, inp, and outp); those are
documented with the CP/M services rather than treated as portable C APIs.
Dynamic memory¶
The allocator uses a first-fit heap walk with two-byte packed boundary tags at
the start and end of each block. Freeing a block coalesces it with adjacent free
neighbours (including blocks freed via realloc(p, 0) and the old block
released by a growing realloc), which keeps fragmentation down. realloc
also grows in place at the heap top or into an immediately following free
block. The heap grows on demand between the end of BSS and the stack. On CP/M
this space is bounded by the program's TPA: code, data, runtime support, heap,
and stack all share the same transient program area.
char *p = malloc(256);
if (!p) { fputs("out of memory\n", stderr); exit(EXIT_FAILURE); }
p = realloc(p, 512); /* old contents preserved */
free(p);
realloc follows the standard rules: realloc(NULL, n) behaves like
malloc(n), and realloc(p, 0) frees p and returns NULL.
Size cost
malloc/calloc link integer multiply/divide/modulo helpers for size
arithmetic, and strdup inherits the whole malloc chain. See the
appendix.
Conversion¶
atoi/atol skip leading spaces/tabs, accept an optional +/- sign, then
consume decimal digits; conversion stops at the first non-digit. Overflow wraps
modulo the type width.
int n = atoi(" -123xyz"); /* -123 */
long m = atol(" -123456"); /* -123456L */
strtol/strtoul are the full C89 conversions. They skip leading whitespace,
accept an optional sign, honour a 0x/0X prefix for base 16 and a leading 0
for base 8 when base is 0, and accept digits/letters up to base-1 for any
base from 2 to 36. The unused tail is reported through *end when end is
non-NULL. On overflow they clamp to LONG_MAX/LONG_MIN (or ULONG_MAX) and
set errno to ERANGE.
char *end;
long v = strtol(" -0x1Ag", &end, 0); /* v = -26, *end = 'g' */
unsigned long u = strtoul("4294967295", NULL, 10); /* ULONG_MAX */
atof is available as a DCC C Compiler extension: it is declared as float atof(const char *nptr)
and returns IEEE 754 single precision. C89 atof normally returns double, which DCC C Compiler
does not have. It accepts ordinary decimal text with an optional exponent, plus the case-insensitive
spellings nan, inf, and infinity. Overflow returns signed infinity; underflow returns signed zero.
Integer arithmetic helpers¶
div returns a div_t with quot and rem members; ldiv returns an
ldiv_t with 32-bit members. Signed division truncates toward zero; the
remainder has the same sign as the numerator.
div_t d = div(-7, 3); /* d.quot == -2, d.rem == -1 */
ldiv_t ld = ldiv(200000L, 7L);
Searching and sorting¶
Both take the standard comparator: cmp(a, b) returns negative if a sorts
before b, zero if equal, positive if after. qsort uses an in-place,
non-recursive Shell sort, so it is not stable; bsearch requires the array
to be sorted by the same comparator. See Worked examples for
complete programs.
Process control¶
The exit code is surfaced through CP/M 3.0 BDOS call 108, which emulators such
as ntvcm reflect in their own process exit code. Returning a value from main
has the same effect.
Pseudo-random numbers¶
RAND_MAX is 32767.
srand(1);
int roll = rand() % 6 + 1; /* a die roll */
The runtime generator is a 16-bit xorshift with parameters 7, 9, and 8. The
state is 16-bit, srand(seed) stores the state directly, and rand() clears
bit 15 of the updated state so the result stays in the C89 0 .. RAND_MAX
range. In C-equivalent form:
static unsigned int s_rnd = 1;
void srand(unsigned int seed)
{
s_rnd = seed;
}
int rand(void)
{
s_rnd ^= s_rnd << 7;
s_rnd ^= s_rnd >> 9;
s_rnd ^= s_rnd << 8;
return (int)(s_rnd & 0x7fff);
}
That deterministic sequence is useful for benchmarks: if another CP/M compiler
uses the same C equivalent, tests that depend on rand() can compare runtime
library and code-generation performance without being skewed by different
pseudo-random sequences.