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.6 const and volatile

The keyword const was one of the C++ features included in ISO C. When the analogous keyword, volatile, was invented by the ISO C Committee, the type qualifier category was created.

6.6.1 Types for lvalue Only

const and volatile are part of an identifier’s type, not its storage class. However, they are often removed from the topmost part of the type when an object’s value is fetched in the evaluation of an expression, exactly at the point when an lvalue becomes an rvalue. These terms arise from the prototypical assignment left-hand-side=right-hand-side; in which the left side must still refer directly to an object (an lvalue) and the right side need only be a value (an rvalue). Thus, only expressions that are lvalues can be qualified by const or volatile or both.

6.6.2 Type Qualifiers in Derived Types

The type qualifiers may modify type names and derived types. Derived types are those parts of declarations in C that can be applied repeatedly to build more and more complex types: pointers, arrays, functions, structures, and unions. Except for functions, one or both type qualifiers can be used to change the behavior of a derived type.

The following example declares and initializes an object with type const int whose value is not changed by a correct program.

const int five = 5;

The order of the keywords is not significant to C. For example, the following declarations are identical to the first example in its effect:

int const five = 5;
const five = 5;

The following declaration declares an object with type pointer to const int, which initially points to the previously declared object.

const int *pci = &five;

The pointer itself does not have a qualified type, but rather it points to a qualified type. It can be changed to point to essentially any int during program execution. pci cannot be used to modify the object to which it points unless a cast is used, as in the following example:

*(int *)pci = 17;

If pci actually points to a const object, the behavior of this code is undefined.

The following declaration indicates that somewhere in the program is a definition of a global object with type const pointer to int.

extern int *const cpi;

In this case, cpi’s value will not be changed by a correct program, but it can be used to modify the object to which it points. Notice that const comes after the * in the declaration. The following pair of declarations produces the same effect:

typedef int *INT_PTR;
extern const INT_PTR cpi;

These declarations can be combined as in the following declaration in which an object is declared to have type const pointer to const int:

const int *const cpci;
  

6.6.3 const Means readonly

In hindsight, readonly would have been a better choice for a keyword than const. If one reads const in this manner, declarations such as the following example, are easily understood to mean that the second parameter is only used to read character values, while the first parameter overwrites the characters to which it points. :

char *strcpy(char *, const char *);

Furthermore, despite the fact that in the example the type of cpi is a pointer to a const int, you can still change the value of the object to which it points through some other means, unless it actually points to an object declared with const int type.

6.6.4 Examples of const Usage

The two main uses for const are to declare large compile-time initialized tables of information as unchanging, and to specify that pointer parameters do not modify the objects to which they point.

The first use potentially allows portions of the data for a program to be shared by other concurrent invocations of the same program. It might cause attempts to modify this invariant data to be detected immediately by means of some sort of memory protection fault, because the data resides in a read-only portion of memory.

The second use of const helps locate potential errors before generating a memory fault. For example, functions that temporarily place a null character into the middle of a string are detected at compile time, if passed a pointer to a string that cannot be so modified.

6.6.5 Examples of volatile Usage

So far, the examples have shown const to be conceptually simple. But what does volatile really mean? For the compiler, it means don't take any code generation shortcuts when accessing such an object. On the other hand, ISO C makes it the programmer's responsibility to declare volatile every object that has the appropriate special properties.

The usual four examples of volatile objects are:

The first three examples are all instances of an object with a particular behavior: its value can be modified at any point during the execution of the program. Thus, the following seemingly infinite loop is valid as long as flag has a volatile qualified type.

flag = 1;
while (flag);

Presumably, some asynchronous event sets flag to zero in the future. Otherwise, because the value of flag is unchanged within the body of the loop, the compilation system is free to change the above loop into a truly infinite loop that completely ignores the value of flag.

The fourth example, involving variables local to functions that call setjmp, is more involved. The details about the behavior of setjmp and longjmp indicates that the values for objects matching the fourth case are unpredictable. For the most desirable behavior, longjmp must examine every stack frame between the function calling setjmp and the function calling longjmp for saved register values. The possibility of asynchronously created stack frames makes this job even harder.

When an automatic object is declared with a volatile qualified type, the compiler must generate code that exactly matches what the programmer wrote. Therefore, the most recent value for such an automatic object is always in memory and not just in a register, and is guaranteed to be up-to-date when longjmp is called.