This section admittedly contains very little information if compared to Portable C Software [4]. We direct the reader to that reference for more information.
Time and time again, it happens that the target platform does not have all the library functions needed by a given application. This is particularly true with mathematical functions. We would like to remind the reader that the sources to 4.3BSD are publicly available, and may be obtained at several sites, e.g., funic.funet.fi [128.214.6.100] in ~ftp/pub/bsd-sources, the contents of which are cloned from uunet.uu.net. Read the copyright notices before using them.
cbrt(x) evaluates the cube root of its argument, that is, x^1/3. pow(x,y) evaluates x^y. Some systems implement neither of these, or just the latter. In that case, one can define pow as a function of exp and log, and if one has pow but not cbrt, one can write the latter as a function of the former:
#define pow(x,y) (exp(log(x)*(y))) #define cbrt(x) (pow((x),1./3.))
Thus defined, pow only admits strictly positive arguments. If the argument x is negative, then a result can be evaluated if y is an integer and one must implement such a function oneself (a predicate which determines if y is an integer is usually not available).
The definitions given above are a "poor man's" solution to the problem but acceptable in many situations. In order to obtain numerically robust and accurate results one must investigate other alternatives such as obtaining the source code for the 4.3BSD implementation via anonymous FTP as mentioned at the beginning of this Section.
It should be mentioned that if the argument y is zero then implementations differ on the result. The 4.3BSD implementation returns always 1.0; others may return undefined values, flag an error, or return not-a-number.
rand returns a pseudo-random integer in the range 0 to RAND_MAX, which is guaranteed only to be at least 32,767. Do not rely on rand returning results over a much wider range.
alloca(n) allocates the amount of bytes specified by n and returns a pointer to the allocated memory. This space is -- for all practical purposes -- automatically deallocated (freed) when the block scope is exited. More specifically, the storage is deallocated no sooner than the exit from the block scope; the implementation is allowed to do the freeing at function exit, upon the next call to alloca, or at any other moment deemed appropriate. The example below illustrates incorrect usage of alloca:
foo ()
{
char *sto;
{
sto = alloca (10);
use (sto); /* Correct. */
}
use (sto); /* Error: storage may have been freed. */
}
Conceptually, the space is allocated on a stack, so allocation can be as fast as just adjusting the stack pointer if the machine has one, and several regions can be freed at once by simply readjusting the stack pointer. However, it is hard to implement alloca both portably and efficiently. alloca is not available on all platforms and as such is not required by the Standard. However, there are public domain implementations that work in a wide variety of cases, but which can be slow and which can delay freeing arbitrarily (10).
Thus, while it is very desirable to use alloca when it is available, because of efficiency considerations, it is highly recommended that the code be written so that malloc and free can easily replace it, if and when necessary.
bcopy(s1,s2,n) copies the string s1 into s2, whereas memcpy(s1,s2,n) copies s2 into s1. bcopy can be found in BSD-like systems, and some implementations handle overlapping strings, while others do not. memcpy and memmove are implemented in the other camp (System V); memcpy does not handle overlapping strings, whereas memmove does.
The normal solution is to use macros.
bzero(s,n) is equivalent to memset(s,0,n). The former is implemented in BSD-like systems, whereas the latter is implemented in System V-like systems and is required by the Standard.
See also Initialization in section 11.2.4.
malloc is available in all C implementations and its behavior is very well defined except in boundary conditions. Not all implementations accept a zero-sized request. There are other minor differences such as the return type being char * in some implementations and void * in others.
In a similar vein, some implementations of free do not accept NULL as an argument. Worse, though, is that some implementations allowed the caller to use the pointer even after it had been freed so long as no other call to malloc was performed. Relying on such behavior is bad.
realloc(sto,n) takes a pointer to a region allocated with malloc and grows or shrinks the region so that it is of size n. The return value from realloc is a pointer to the resized storage; if the storage was grown "in place", the return value is the same as sto. If the region was moved, then the old contents are copied to the new storage (if n is smaller than the old size, then only the first n units are copied). If the region is grown, the new storage at the end is uninitialized and may contain garbage.
Under ANSI C:
For non-ANSI versions of realloc, specifying NULL as the storage or 0 as the new size causes undefined behavior. Thus, it is recommended that portable programs, even those written in ANSI C, not use these features. If it is necessary to rely on those features, use a macro or write a function that can be configured to check for those cases explicitly.
Some versions of the scanf family modify and then restore arguments which are string constants. These implementations cause problems when string constants are placed in read-only memory (see {"String constants"} in section 11.2.4). If the string is actually a constant, then some workaround is needed; usually a compiler flag may be used to indicate that such constants should be placed in writable memory instead. If such a flag is not available then the code must be modified.
In other words, it is not that you should not use them but be careful if you do. Furthermore, the behavior of a longjmp invoked from a nested signal handler (11) is undefined.
Finally, the symbols _setjmp and _longjmp are only defined under SunOS, BSD, and HP-UX. Some systems do not implement setjmp and friends at all.
We would like to point out one problem when handling signals generated by hardware, such as SIGFPE and SIGSEGV. There are two possibilities on a normal exit from the signal handler: (i) the offending instruction is re-executed, or (ii) it is not.
The first possibility may cause an infinite loop, and the only portable solution is to longjmp out of the signal handler.
11. That is, a function invoked as a result of a signal raised during the handling of another signal. See section 4.6.2.1, paragraph 15 in the Standard [13].
contents
Header Files
Using Floating-Point Numbers