C Programming - Standard Library Functions

9.
What's a signal? What do I use signals for?
A signal is an exceptional condition that occurs during the execution of your program. It might be the result of an error in your program, such as a reference to an illegal address in memory; or an error in your program's data, such as a floating-point divided by 0; or an outside event, such as the user's pressing Ctrl-Break. The standard library function signal() enables you to specify what action is to be taken on one of these exceptional conditions (a function that performs that action is called a "signal handler"). The prototype for signal() is

#include <signal.h>

void (*signal(int num, void (*func)(int)))(int);

which is just about the most complicated declaration you'll see in the C standard library. It is easier to understand if you define a typedef first. The type sigHandler_t, shown next, is a pointer to a function that takes an int as its argument and returns a void:

typedef void (*sigHandler_t)(int);

sigHandler_t signal(int num, sigHandler_t func);

signal() is a function that takes an int and a sigHandler_t as its two arguments, and returns a sigHandler_t as its return value. The function passed in as the func argument will be the new signal handler for the exceptional condition numbered num. The return value is the previous signal handler for signal num. This value can be used to restore the previous behavior of a program, after temporarily setting a signal handler. The possible values for num are system dependent and are listed in signal.h. The possible values for func are any function in your program, or one of the two specially defined values SIG_DFL or SIG_IGN. The SIG_DFL value refers to the system's default action, which is usually to halt the program. SIG_IGN means that the signal is ignored.

The following line of code, when executed, causes the program containing it to ignore Ctrl-Break keystrokes unless the signal is changed again. Although the signal numbers are system dependent, the signal number SIGINT is normally used to refer to an attempt by the user to interrupt the program's execution (Ctrl-C or Ctrl-Break in DOS):

signal(SIGINT, SIG_IGN);


10.
Why shouldn't I start variable names with underscores?

Identifier names beginning with two underscores or an underscore followed by a capital letter are reserved for use by the compiler or standard library functions wherever they appear. In addition, all identifier names beginning with an underscore followed by anything are reserved when they appear in file scope (when they are not local to a function).

If you use a reserved identifier for a variable name, the results are undefined (your program might not compile, or it might compile but crash). Even if you are lucky enough to pick an identifier that is not currently used by your compiler or library, remember that these identifiers are reserved for possible use later. Thus, it's best to avoid using an underscore at the beginning of variable and function names.


11.
What math functions are available for integers? For floating point?

The operations +, -, *, and / (addition, subtraction, multiplication, and division) are available for both integer and floating-point arithmetic. The operator % (remainder) is available for integers only.

For floating-point math, many other functions are declared in the header file math.h. Most of these functions operate in double-precision floating point, for increased accuracy. If these functions are passed an argument outside of their domain (the domain of a function is the set of legal values for which it is defined), the function will return some unspecified value and will set the variable errno to the value EDOM. If the return value of the function is too large or small to be represented by a double (causing overflow or underflow), the function will return HUGE_VAL (for overflow) or 0 (for underflow) and will set errno to ERANGE. The values EDOM, ERANGE, and HUGE_VAL are defined in math.h.

The following list describes the functions declared in math.h:

1. double cos(double), double sin(double), double tan(double) take a value in radians and return the cosine, sine, and tangent of the value, respectively.

2. double acos(double), double asin(double), double atan(double) take a value and return the arc cosine, arc sine, and arc tangent of the value, respectively. The value passed to acos() and asin() must be in the range -1 to 1, inclusive.

3. double atan2(double x, double y) returns the arc tangent of the value represented by x/y, even if x/y is not representable as a double (if y is 0, for instance).

4. double cosh(double), double sinh(double), double tanh(double) take a value in radians and return the hyperbolic cosine, hyperbolic sine, and hyperbolic tangent of the value, respectively.

5. double exp(double x), double log(double x), double log10(double x) take a value and return ex, the natural logarithm of x, and the logarithm base 10 of x, respectively. The two logarithm functions will cause a range error (ERANGE) if x is 0 and a domain error (EDOM) if x is negative.

6. double sqrt(double) returns the square root of its argument. It causes a domain error (EDOM) if the value passed to it is negative.

7. double ldexp(double n, int e) returns n * 2e. This is somewhat analogous to the << operator for integers.

8. double pow(double b, double e) returns be. It causes a domain error (EDOM) if b is 0 and e is less than or equal to 0, or if b is less than 0 and e is not an integral value.

9. double frexp(double n, int *i) returns the mantissa of n and sets the int pointed to by i to the exponent of n. The mantissa is in the range 0.5 to 1 (excluding 1 itself ), and the exponent is a number such that n = mantissa * 2exponent.

10. double modf(double n, int *i) returns the fractional part of n and sets the int pointed to by i to the integer part of n.

11. double ceil(double), double floor(double) return the smallest integer greater than or equal to and the largest integer less than or equal to their arguments, respectively. For instance, ceil(-1.1) returns -1.0, and floor(-1.1) returns -2.0.

12. double fmod(double x, double y) returns the remainder of x/y. This is similar to the % operator for integers, but it does not restrict its inputs or result to be ints. It causes a domain error (EDOM) if y is 0.

13. double fabs(double) returns the absolute value of the value passed to it (a number with the same magnitude, but always positive). For instance, fabs(-3.14) returns 3.14.


12.
What are multibyte characters?

Multibyte characters are another way to make internationalized programs easier to write. Specifically, they help support languages such as Chinese and Japanese that could never fit into eight-bit characters. If your programs will never need to deal with any language but English, you don't need to know about multibyte characters.

Inconsiderate as it might seem, in a world full of people who might want to use your software, not everybody reads English. The good news is that there are standards for fitting the various special characters of European languages into an eight-bit character set. (The bad news is that there are several such standards, and they don't agree.)

Go to Asia, and the problem gets more complicated. Some languages, such as Japanese and Chinese, have more than 256 characters. Those will never fit into any eight-bit character set. (An eight-bit character can store a number between 0 and 255, so it can have only 256 different values.)

The good news is that the standard library has the beginnings of a solution to this problem. <stddef.h> defines a type, wchar_t, that is guaranteed to be long enough to store any character in any language a C program can deal with. Based on all the agreements so far, 16 bits is enough. That's often a short, but it's better to trust that the compiler vendor got wchar_t right than to get in trouble if the size of a short changes.

The mblen, mbtowc, and wctomb functions transform byte strings into multibyte characters. See your compiler manuals for more information on these functions.