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

Document Information

Preface

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 New-Style Function Prototypes

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 Some Background History

6.4.2 Compilation Behavior

6.4.3 Example: The Use of a Cast

6.4.4 Example: Same Result, No Warning

6.4.5 Integral Constants

6.4.6 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 for lvalue Only

6.6.2 Type Qualifiers in Derived Types

6.6.3 const Means readonly

6.6.4 Examples of const Usage

6.6.5 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 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 setlocale() Function

6.9.3 Changed Functions

6.9.4 New Functions

6.10 Grouping and Evaluation in Expressions

6.10.1 Expression Definitions

6.10.2 K&R C Rearrangement License

6.10.3 ISO C Rules

6.10.4 Parentheses Usage

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: Incomplete Types

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.  Features of C99

E.  Implementation-Defined ISO/IEC C90 Behavior

F.  ISO C Data Representations

G.  Performance Tuning

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

Index

6.2 New-Style Function Prototypes

The 1990 ISO C standard’s most sweeping change to the language is the function prototype borrowed from the C++ language. By specifying the number and types of parameters for each function, every regular compile gets the benefits of argument and parameter checking (similar to those of lint) for each function call, while 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 someone might port the code to a system with a pre-ISO C compiler, 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, a number of possibilities for updating exist, 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 only 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 this method 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, you cannot mix ISO C’s ellipsis notation and the old-style varargs() function definition. For functions with a fixed number of parameters, you can 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, which simplified both the compiler and libraries. Function prototypes are more expressive, as 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,the function prototype should not contain any parameters with any of the following types: char, signed char, unsigned char, float, short, signed short, unsigned short.

Two complications remain 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, you must know whether the typedef name designates a type that is affected by the default argument promotions. For these two, off_t is a long, you can use it 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.

Determining what should be used instead of an unsigned short is complicated. The 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 this 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.

Be carefule about 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:

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

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

struct s *
#ifdef __STDC__
    f(const char *p)
#else
    f(p) char *p;
#endif
{
    /* .  .  .  */
}

The following example shows 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:

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