C and math library overview
To Contents | To previous page | To next page

## C and math library overview

eCos provides compatibility with the ISO 9899:1990 specification for the standard C library, which is essentially the same as the better-known ANSI C3.159-1989 specification (C-89).

There are three aspects of this compatibility supplied by eCos. First there is a C library which implements the functions defined by the ISO standard, except for the mathematical functions. This is provided by the eCos C library package.

Then eCos provides a math library , which implements the mathematical functions from the ISO C library. This distinction between C and math libraries is frequently drawn -- most standard C library implementations provide separate linkable files for the two, and the math library contains all the functions from the `math.h` header file.

There is a third element to the ISO C library, which is the environment in which applications run when they use the standard C library. This environment is set up by the C library startup procedure (see C library startup ) and it provides (among other things) a `main()` entry point function, an `exit()` function that does the cleanup required by the standard (including handlers registered using the `atexit()` function), and an environment that can be read with `getenv()` .

The description in this manual focuses on the eCos -specific aspects of the C library (mostly related to eCos 's configurability) as well as mentioning the omissions from the standard in this release. We do not attempt to define the semantics of each function, since that information can be found in the ISO, ANSI, POSIX and IEEE standards, and the many good books that have been written about the standard C library, that cover usage of these functions in a more general and useful way.

### Omitted functionality

The ISO C functionality that is currently omitted in the C library can be grouped by the header files in which they are declared:

### stdio.h

`remove()`

`rename()`

`tmpfile()`

`tmpnam()`

`fseek()`

`ftell()`

`rewind()`

`fgetpos()`

`fsetpos()`

Most of these functions are omitted because they only apply to disk-based file systems. These will be supported in a future version of eCos.

### stdlib.h

`mblen()`

`mbtowc()`

`wctomb()`

`mbstowcs()`

`wcstombs()`

`MB_CUR_MAX`

All of these functions are related to multibyte and wide character support.

### Included non-ISO functions

The following functions from the POSIX specification are included for convenience:

`extern char **` environ variable (for setting up the environment for use with `getenv()` )

`_exit()`

`strtok_r()`

`rand_r()`

`asctime_r()`

`ctime_r()`

`localtime_r()`

`gmtime_r()`

eCos provides the following additional implementation-specific functions within the standard C library to adjust the date and time settings:

    void cyg_libc_time_setdst
    (

    cyg_libc_time_dst state );

This function sets the state of Daylight Savings Time. The values for state are:

    CYG_LIBC_TIME_DSTNA   unknown

    CYG_LIBC_TIME_DSTOFF  off

    CYG_LIBC_TIME_DSTON   on

    void cyg_libc_time_setzoneoffsets
    (

    time_t stdoffset, time_t dstoffset);

This function sets the offsets from UTC used when Daylight Savings Time is enabled or disabled. The offsets are in time_t's, which are seconds in the current inplementation.

    Cyg_libc_time_dst cyg_libc_time_getzoneoffsets
    (

    time_t *stdoffset, time_t *dstoffset);

This function retrieves the current setting for Daylight Savings Time along with the offsets used for both STD and DST. The offsets are both in time_t's, which are seconds in the current implementation.

    cyg_bool cyg_libc_time_settime
    (

    time_t utctime);

This function sets the current time for the system The time is specified as a `time_t` in UTC. It returns non-zero on error.

### Math library compatibility modes

This math library is capable of being operated in several different compatibility modes. These options deal solely with how errors are handled.

There are 4 compatibility modes: ANSI/POSIX 1003.1; IEEE-754; X/Open Portability Guide issue 3 (XPG3); and System V Interface Definition Edition 3.

In IEEE mode, the `matherr()` function (see below) is never called, no warning messages are printed on the stderr output stream, and errno is never set.

In ANSI/POSIX mode, errno is set correctly, but `matherr()` is never called and no warning messages are printed on the stderr output stream.

In X/Open mode, errno is set correctly, `matherr()` is called, but no warning messages are printed on the stderr output stream.

In SVID mode, functions which overflow return a value HUGE (defined in `math.h` ), which is the maximum single precision floating point value (as opposed to HUGE_VAL which is meant to stand for infinity). errno is set correctly and `matherr()` is called. If `matherr()` returns 0, warning messages are printed on the stderr output stream for some errors.

The mode can be compiled-in as IEEE-only, or any one of the above methods settable at run-time.

### NOTE

This math library assumes that the hardware (or software floating point emulation) supports IEEE-754 style arithmetic, 32-bit 2's complement integer arithmetic, doubles are in 64-bit IEEE-754 format.

### matherr()

As mentioned above, in X/Open or SVID modes, the user can supply a function `matherr()` of the form:

    int matherr
    (

    struct exception *e )

where struct exception is defined as:

    struct exception {
     int type;
     char *name;
     double arg1, arg2, retval;
    };

type is the exception type and is one of:

DOMAIN

argument domain exception

SING

argument singularity

OVERFLOW

overflow range exception

UNDERFLOW

underflow range exception

TLOSS

total loss of significance

PLOSS

partial loss of significance

name is a string containing the name of the function

arg1 and arg2 are the arguments passed to the function

retval is the default value that will be returned by the function, and can be changed by `matherr()`

### NOTE

matherr must have "C" linkage, not "C++" linkage.

If matherr returns zero, or the user doesn't supply their own matherr, then the following usually happens in SVID mode:

Behavior of math exception handling

Type | Behavior
--- | ---
DOMAIN | 0.0 returned, errno=EDOM, and a message printed on stderr
SING | HUGE of appropriate sign is returned, errno=EDOM, and a message is printed on stderr
OVERFLOW | HUGE of appropriate sign is returned, and errno=ERANGE
UNDERFLOW | 0.0 is returned and errno=ERANGE
TLOSS | 0.0 is returned, errno=ERANGE, and a message is printed on stderr
PLOSS | The current implementation doesn't return this type

X/Open mode is similar except that the message is not printed on stderr and HUGE_VAL is used in place of HUGE

### Thread-safety and re-entrancy

With the appropriate configuration options set below, the math library is fully thread-safe if:

- Depending on the compatibility mode, the setting of the errno variable from the C library is thread-safe

- Depending on the compatibility mode, sending error messages to the stderr output stream using the C library `fputs()` function is thread-safe

- Depending on the compatibility mode, the user-supplied `matherr()` function and anything it depends on are thread-safe

In addition, with the exception of the `gamma*()` and `lgamma*()` functions, the math library is reentrant (and thus safe to use from interrupt handlers) if the Math library is always in IEEE mode.

### Some implementation details

Here are some details about the implementation which might be interesting, although they do not affect the ISO-defined semantics of the library.

- It is possible to configure eCos to have the standard C library without the kernel. You might want to do this to use less memory. But if you disable the kernel, you will be unable to use memory allocation, thread-safety and certain stdio functions such as input. Other C library functionality is unaffected.

- The opaque type returned by `clock()` is called clock_t, and is implemented as a 64 bit integer. The value returned by `clock()` is only correct if the kernel is configured with real-time clock support, as determined by the CYGVAR_KERNEL_COUNTERS_CLOCK configuration option in `kernel.h` .

- The FILE type is not implemented as a structure, but rather as a CYG_ADDRESS.

- The GNU C compiler will place its own built-in implementations instead of some C library functions. This can be turned off with the -fno-builtin option. The functions affected by this are `abs()` , `cos()` , `fabs()` , `labs()` , `memcmp()` , `memcpy()` , `sin()` , `sqrt()` , `strcmp()` , `strcpy()` , and `strlen()` .

- For faster execution speed you should avoid this option and let the compiler use its built-ins. This can be turned off by invoking GCC with the -fno-builtin option.

- `memcpy()` and `memset()` are located in the infrastructure package, not in the C library package. This is because the compiler calls these functions, and the kernel needs to resolve them even if the C library is not configured.

- Error codes such as EDOM and ERANGE, as well as `strerror()` , are implemented in the error package. The error package is separate from the rest of the C and math libraries so that the rest of eCos can use these error handling facilities even if the C library is not configured.

- When `free()` is invoked, heap memory will normally be coalesced. If the CYGSEM_KERNEL_MEMORY_COALESCE configuration parameter is not set, memory will not be coalesced, which might cause programs to fail.

- Signals, as implemented by `<signal.h>` , are guaranteed to work correctly if raised using the `raise()` function from a normal working program context. Using signals from within an ISR or DSR context is not expected to work. Also, it is not guaranteed that if CYGSEM_LIBC_SIGNALS_HWEXCEPTIONS is set, that handling a signal using `signal()` will necessarily catch that form of exception. For example, it may be expected that a divide-by-zero error would be caught by handling `SIGFPE` . However it depends on the underlying HAL implementation to implement the required hardware exception. And indeed the hardware itself may not be capable of detecting these exceptions so it may not be possible for the HAL implementer to do this in any case. Despite this lack of guarantees in this respect, the signals implementation is still ISO C compliant since ISO C does not offer any such guarantees either.

- The `getenv()` function is implemented (unless the CYGPKG_LIBC_ENVIRONMENT configuration option is turned off), but there is no shell or `putenv()` function to set the environment dynamically. The environment is set in a global variable environ, declared as:

    extern char **environ; // Standard environment definition

The environment can be statically initialized at startup time using the CYGDAT_LIBC_DEFAULT_ENVIRONMENT option. If so, remember that the final entry of the array initializer must be NULL.

Here is a minimal eCos program which demonstrates the use of environments (see also the test case in `language/c/libc/current/tests/stdlib/getenv.c` ):

    #include <stdio.h>
    #include <stdlib.h> // Main header for stdlib functions

    extern char **environ; // Standard environment definition

    int
    main( int argc, char *argv[] )
    {
     char *str;
     char *env[] = { "PATH=/usr/local/bin:/usr/bin",
     "HOME=/home/fred",
     "TEST=1234=5678",
     "home=hatstand",
     NULL };

     printf("Display the current PATH environment variable\n");

     environ = (char **)&env;

     str = getenv("PATH");

     if (str==NULL) {
     printf("The current PATH is unset\n");
     } else {
     printf("The current PATH is \"%s\"\n", str);
     }
     return 0;
    }

### Thread safety

The ISO C library has configuration options that control thread safety, i.e. working behavior if multiple threads call the same function at the same time.

The following functionality has to be configured correctly, or used carefully in a multi-threaded environment:

- `printf()` (and all standard I/O functions except for `sprintf()` and `sscanf()`

- `strtok()`

- `rand()` and `srand()`

- `signal()` and `raise()`

- `asctime()` , `ctime()` , `gmtime()` , and `localtime()`

- the `errno` variable

- the `environ` variable

- date and time settings

In some cases, to make eCos development easier, functions are provided (as specified by POSIX 1003.1) that define re-entrant alternatives, i.e. `rand_r()` , `strtok_r()` , `asctime_r()` , `ctime_r()` , `gmtime_r()` , and `localtime_r()` . In other cases, configuration options are provided that control either locking of functions or their shared data, such as with standard I/O streams, or by using per-thread data, such as with the `errno` variable.

In some other cases, like the setting of date and time, no re-entrant or thread-safe alternative or configuration is provided as it is simply not a worthwhile addition (date and time should rarely need to be set.)

### C library startup

The C library includes a function declared as:

    void cyg_iso_c_start
    ( void )

This function is used to start an environment in which an ISO C style program can run in the most compatible way.

What this function does is to create a thread which will invoke `main()` -- normally considered a program's entry point. In particular, it can supply arguments to `main()` using the CYGDAT_LIBC_ARGUMENTS configuration option (see "Option: Arguments to main()", in Section V), and when returning from `main()` , or calling `exit()` , pending stdio file output is flushed and any functions registered with `atexit()` are invoked. This is all compliant with the ISO C standard in this respect.

This thread starts execution when the eCos scheduler is started. If the eCos kernel package is not available (and hence there is no scheduler), then `cyg_iso_c_start()` will invoke the `main()` function directly, i.e. it will not return until the `main()` function returns.

The `main()` function should be defined as the following, and if defined in a C++ file, should have "C" linkage:

    extern int main
    (

    int argc,

    char *argv )
    []

The thread that is started by `cyg_iso_c_start()` can be manipulated directly, if you wish. For example you can suspend it. The kernel C API needs a handle to do this, which is available by including the following in your source code.

    extern cyg_handle_t cyg_libc_main_thread;

Then for example, you can suspend the thread with the line:

    cyg_thread_suspend( cyg_libc_main_thread );

If you call `cyg_iso_c_start()` and do not provide your own `main()` function, the system will provide a `main()` for you which will simply return immediately.

In the default configuration, `cyg_iso_c_start()` is invoked automatically by the `cyg_package_start()` function in the infrastructure configuration. This means that in the simplest case, your program can indeed consist of simply:

    int main( int argc, char *argv[] )
    {
     printf("Hello eCos\n");
    }

If you override `cyg_package_start()` or `cyg_start()` , or disable the infrastructure configuration option CYGSEM_START_ISO_C_COMPATIBILITY then you must ensure that you call `cyg_iso_c_start()` yourself if you want to be able to have your program start at the entry point of `main()` automatically.

####
Index

C and math library overview
To Contents | To previous page | To next page