# PCC compatibility mode

This section discusses the differences apparent when the compiler is used in PCC mode. When given the -pcc command line flag, the C compiler will accept (Berkeley) Unix-compatible C, as defined by the implementation of the Portable C Compiler and subject to the restrictions which are noted below.

In essence, PCC-style C is K&R C, as defined by B. Kernighan and D. Ritchie in their book The C Programming Language, together with a small number of extensions, and some clarifications of language features that the book leaves undefined.

## Language and preprocessor compatibility

In -pcc mode, the ARM C compiler accepts K&R C, but it does not accept many of pcc's old-style compatibility features, the use of which has been deprecated and warned against for years. The differences are:

- Compound assignment operators where the = sign comes first are accepted (with a warning) by some PCCs. An example is =+ instead of +=. ARM C does not allow this ordering of the characters in the token.

- The = sign before a static initialiser was not required by some very old C compilers. ARM C does not support this idiom.

- The following very peculiar usage is found in some Unix tools pre-dating Unix Version 7:

      struct {int a, b;};
      double d;
      d.a = 0; d.b = 0x....;

This is accepted by some Unix PCCs and may cause problems when porting old (and badly written) code:

- Enums are less strongly typed than is usual under PCCs. Enum is an extension to K&R C which has been standardised by ANSI somewhat differently from the BSD PCC implementation.
- Chars are signed by default in -pcc mode (unsigned in ANSI mode).
- In -pcc mode, the compiler permits the use of the ANSI ... notation which signifies that a variable number of formal arguments follow.
- In order to cater for PCC-style use of variadic functions, a version of the PCC header file varargs.h is supplied with the release.

With the exception of enums, the compiler's type checking is generally stricter than PCC, much more akin to lint's, in fact. In writing the ARM C compiler, we have attempted to strike a balance between giving too many warnings when compiling known, working code, and warning of poor or non portable programming practices. Many PCCs silently compile code which has no chance of executing in just a slightly different environment. We have tried to be helpful to those who need to port C among machines in which the following varies:

- the order of bytes within a word (e.g. little-endian ARM, VAX, Intel versus big-endian Motorola, IBM370);

- the default size of int (four bytes versus two bytes in many PC implementations);

- the default size of pointers (not always the same as int);

- whether values of type char default to signed or unsigned char;

- the default handling of undefined and implementation-defined aspects of the C language.

The compiler's preprocessor is believed to be equivalent to a BSD Unix cpp except for the points listed below. Unfortunately, cpp is only defined by its implementation, and although equivalence has been tested over a large body of Unix source code, completely identical behaviour cannot be guaranteed. Some of the points listed below only apply when the -E option is used with the cc command:

- There is a different treatment of white space sequences (benign).

- Newline is processed by cc -E, but passed by cpp (making lines longer than expected; (cc -E only).

- Cpp breaks long lines at a token boundary; cc -E does not. This may break line-size constraints when the source is later consumed by another program (cc -E only).

- The handling of unrecognised directives is different (this is mostly benign).

## Standard headers and libraries

Use of the compiler in -pcc mode precludes neither the use of the standard ANSI headers built in to the compiler nor the use of the run-time library supplied with the C compiler. Of course, the ANSI library does not contain the whole of the Unix C library, but it does contain many commonly used functions. However, look out for functions with different names, or a slightly different definition, or those in different standard places. Unless the user directs otherwise using -j, the C compiler will attempt to satisfy references to, say, stdio.h from its built-in filing system.

Listed below are a number of differences between the ANSI C Library, and the BSD Unix library. They are placed under headings corresponding to the ANSI header files:

### ctype.h

There are no isascii() and toascii() functions, since ANSI C is not character-set specific.

### errno.h

On BSD systems sys_nerr and sys_errlist() are defined to give error messages corresponding to error numbers. ANSI C does not have these, but provides similar functionality via perror(const char *s), which displays the string pointed to by s followed by a system error message corresponding to the current value of errno.

There is also `char *strerror(int errnum)` which, when given a purported value of errno, returns its textual equivalent.

### math.h

The #defined value HUGE, found in BSD libraries, is called HUGE_VAL in ANSI C. ANSI C does not have asinh(), acosh() or atanh().

### signal.h

In ANSI C the signal() function's prototype is:

``

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

`signal()` therefore expects its second argument to be a pointer to a function returning void with one int argument. In BSD-style programs it is common to use a function returning int as a signal handler. The PCC-style function definitions shown below will therefore produce a compiler warning about an implicit cast between different function pointers (since `f()` defaults to`int f()`). This is just a warning, and correct code will be generated anyway.

``

    f(signo)
    int signo;
    ...
    main()
    {   extern f();
        signal(SIGINT, f);
    ...

### stdio.h

`sprintf()` returns the number of characters printed (following Unix System V), whereas the BSD's `sprintf()` returns a pointer to the start of the character buffer.

The BSD functions `ecvt()`, `fcvt()` and `gcvt()` are not included in ANSI C, since their functionality is provided by `sprintf().`

### string.h

On BSD systems, string manipulation functions are found in strings.h whereas ANSI C places them in string.h. The ARM C Compiler also recognises strings.h, for PCC-compatibility.

The BSD functions `index()` and `rindex()` are replaced by the ANSI functions `strchr()` and`strrchr()` respectively.

Functions which refer to string lengths (and other sizes) now use the ANSI type size_t, which in our implementation is unsigned int.

### stdlib.h

`malloc()` has type void *, rather than the char * of the BSD `malloc()`.

### float.h

A new header added by ANSI giving details of floating point precision etc.

### limits.h

A new header added by ANSI to give maximum and minimum limit values for integer data types.

### locale.h

A new header added by ANSI to provide local environment-specific features.