JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Oracle Solaris Studio 12.2: C User's Guide
search filter icon
search icon

Document Information


1.  Introduction to the C Compiler

2.  C-Compiler Implementation-Specific Information

3.  Parallelizing C Code

4.  lint Source Code Checker

5.  Type-Based Alias Analysis

6.  Transitioning to ISO C

6.1 Basic Modes

6.1.1 -Xc

6.1.2 -Xa

6.1.3 -Xt

6.1.4 -Xs

6.2 A Mixture of Old- and New-Style Functions

6.2.1 Writing New Code

6.2.2 Updating Existing Code

6.2.3 Mixing Considerations

6.3 Functions With Varying Arguments

6.4 Promotions: Unsigned Versus Value Preserving

6.4.1 Background

6.4.2 Compilation Behavior

6.4.3 First Example: The Use of a Cast

6.4.4 Bit-fields

6.4.5 Second Example: Same Result

6.4.6 Integral Constants

6.4.7 Third Example: Integral Constants

6.5 Tokenization and Preprocessing

6.5.1 ISO C Translation Phases

6.5.2 Old C Translation Phases

6.5.3 Logical Source Lines

6.5.4 Macro Replacement

6.5.5 Using Strings

6.5.6 Token Pasting

6.6 const and volatile

6.6.1 Types, Only for lvalue

6.6.2 Type Qualifiers in Derived Types

6.6.3 const Means readonly

6.6.4 Examples of const Usage

6.6.5 volatile Means Exact Semantics

6.6.6 Examples of volatile Usage

6.7 Multibyte Characters and Wide Characters

6.7.1 Asian Languages Require Multibyte Characters

6.7.2 Encoding Variations

6.7.3 Wide Characters

6.7.4 Conversion Functions

6.7.5 C Language Features

6.8 Standard Headers and Reserved Names

6.8.1 Standard Headers

6.8.2 Names Reserved for Implementation Use

6.8.3 Names Reserved for Expansion

6.8.4 Names Safe to Use

6.9 Internationalization

6.9.1 Locales

6.9.2 The setlocale() Function

6.9.3 Changed Functions

6.9.4 New Functions

6.10 Grouping and Evaluation in Expressions

6.10.1 Definitions

6.10.2 The K&R C Rearrangement License

6.10.3 The ISO C Rules

6.10.4 The Parentheses

6.10.5 The As If Rule

6.11 Incomplete Types

6.11.1 Types

6.11.2 Completing Incomplete Types

6.11.3 Declarations

6.11.4 Expressions

6.11.5 Justification

6.11.6 Examples

6.12 Compatible and Composite Types

6.12.1 Multiple Declarations

6.12.2 Separate Compilation Compatibility

6.12.3 Single Compilation Compatibility

6.12.4 Compatible Pointer Types

6.12.5 Compatible Array Types

6.12.6 Compatible Function Types

6.12.7 Special Cases

6.12.8 Composite Types

7.  Converting Applications for a 64-Bit Environment

8.  cscope: Interactively Examining a C Program

A.  Compiler Options Grouped by Functionality

B.  C Compiler Options Reference

C.  Implementation-Defined ISO/IEC C99 Behavior

D.  Supported Features of C99

E.  Implementation-Defined ISO/IEC C90 Behavior

F.  ISO C Data Representations

G.  Performance Tuning

H.  The Differences Between K&R Solaris Studio C and Solaris Studio ISO C


6.2 A Mixture of Old- and New-Style Functions

The 1990 ISO C standard’s most sweeping change to the language is the function prototype borrowed from the C++ language. By specifying for each function the number and types of its parameters, not only does every regular compile get the benefits of argument and parameter checks (similar to those of lint) for each function call, but arguments are automatically converted (just as with an assignment) to the type expected by the function. The 1990 ISO C standard includes rules that govern the mixing of old- and new-style function declarations since there are many, many lines of existing C code that could and should be converted to use prototypes.

The 1999 ISO C standard made old-style function declarations obsolete.

6.2.1 Writing New Code

When you write an entirely new program, use new-style function declarations (function prototypes) in headers and new-style function declarations and definitions in other C source files. However, if there is a possibility that someone will port the code to a machine with a pre-ISO C compiler, we suggest you use the macro __STDC__ (which is defined only for ISO C compilation systems) in both header and source files. Refer to 6.2.3 Mixing Considerations for an example.

An ISO C-conforming compiler must issue a diagnostic whenever two incompatible declarations for the same object or function are in the same scope. If all functions are declared and defined with prototypes, and the appropriate headers are included by the correct source files, all calls should agree with the definition of the functions. This protocol eliminates one of the most common C programming mistakes.

6.2.2 Updating Existing Code

If you have an existing application and want the benefits of function prototypes, there are a number of possibilities for updating, depending on how much of the code you would like to change:

  1. Recompile without making any changes.

    Even with no coding changes, the compiler warns you about mismatches in parameter type and number when invoked with the– v option.

  2. Add function prototypes just to the headers.

    All calls to global functions are covered.

  3. Add function prototypes to the headers and start each source file with function prototypes for its local (static) functions.

    All calls to functions are covered, but doing this requires typing the interface for each local function twice in the source file.

  4. Change all function declarations and definitions to use function prototypes.

For most programmers, choices 2 and 3 are probably the best cost/benefit compromise. Unfortunately, these options are precisely the ones that require detailed knowledge of the rules for mixing old and new styles.

6.2.3 Mixing Considerations

For function prototype declarations to work with old-style function definitions, both must specify functionally identical interfaces or have compatible types using ISO C’s terminology.

For functions with varying arguments, there can be no mixing of ISO C’s ellipsis notation and the old-style varargs() function definition. For functions with a fixed number of parameters, the situation is fairly straightforward: just specify the types of the parameters as they were passed in previous implementations.

In K&R C, each argument was converted just before it was passed to the called function according to the default argument promotions. These promotions specified that all integral types narrower than int were promoted to int size, and any float argument was promoted to double, hence simplifying both the compiler and libraries. Function prototypes are more expressive—the specified parameter type is what is passed to the function.

Thus, if a function prototype is written for an existing (old-style) function definition, there should be no parameters in the function prototype with any of the following types:

signed char
unsigned char
signed short
unsigned short

There still remain two complications with writing prototypes: typedef names and the promotion rules for narrow unsigned types.

If parameters in old-style functions were declared using typedef names, such as off_t and ino_t, it is important to know whether or not the typedef name designates a type that is affected by the default argument promotions. For these two, off_t is a long, so it is appropriate to use in a function prototype; ino_t used to be an unsigned short, so if it were used in a prototype, the compiler issues a diagnostic because the old-style definition and the prototype specify different and incompatible interfaces.

Just what should be used instead of an unsigned short leads us into the final complication. The one biggest incompatibility between K&R C and the 1990 ISO C compiler is the promotion rule for the widening of unsigned char and unsigned short to an int value. (See 6.4 Promotions: Unsigned Versus Value Preserving.) The parameter type that matches such an old-style parameter depends on the compilation mode used when you compile:

The best approach is to change the old-style definition to specify either int or unsigned int and use the matching type in the function prototype. You can always assign its value to a local variable with the narrower type, if necessary, after you enter the function.

Watch out for the use of id’s in prototypes that may be affected by preprocessing. Consider the following example:

#define status 23
void my_exit(int status);   /* Normally, scope begins */
                            /* and ends with prototype */

Do not mix function prototypes with old-style function declarations that contain narrow types.

void foo(unsigned char, unsigned short);
void foo(i, j) unsigned char i; unsigned short j; {...}

Appropriate use of __STDC__ produces a header file that can be used for both the old and new compilers:

    struct s { /* .  .  .  */ };
    #ifdef __STDC__
       void errmsg(int, ...);
       struct s *f(const char *);
       int g(void);
      void errmsg();
      struct s *f();
      int g();

The following function uses prototypes and can still be compiled on an older system:

struct s *
#ifdef __STDC__
    f(const char *p)
    f(p) char *p;
    /* .  .  .  */

Here is an updated source file (as with choice 3 above). The local function still uses an old-style definition, but a prototype is included for newer compilers:

   #include “header.h”
      typedef /* .  .  .  */ MyType;
   #ifdef __STDC__
      static void del(MyType *);
      /* .  .  .  */
      static void
      MyType *p;
      /* .  .  .  */
      /* .  .  .  */