═══ 1. How to Use the Online Language Reference ═══ The C/C++ Tools Online Language Reference is a language reference guide for C and C++ programmers. It provides information about the C/C++ Tools implementation of both the C and C++ languages, including code examples, to enable you to write C and C++ programs. This document is a reference rather than a tutorial. It assumes you are already familiar with C and C++ programming concepts. With the exception of the separate introductory sections for each language and the additional C++-specific topics (such as templates and exception handling), information applies to both the C and C++ languages. Differences between the two languages in the implementation of a construct or concept are indicated. Before you begin to use this information, it would be helpful to understand how you can: o Expand the Contents to see all available topics o Obtain additional information for a highlighted word or phrase o Use action bar choices How to Use the Contents When the Contents window first appears, some topics have a plus (+) sign beside them. The plus sign indicates that additional topics are available. To expand the Contents if you are using a mouse, click on the plus sign. If you are using the keyboard, use the Up or Down Arrow key to highlight the topic, and press the plus (+) key. For example, Preprocessor Directives has a plus sign beside it. To see additional topics for that heading, click on the plus sign or highlight that topic and press the plus (+) key. To view a topic, double-click on the topic (or press the Up or Down Arrow key to highlight the topic, and then press the Enter key). How to Obtain Additional Information After you select a topic, the information for that topic appears in a window. Highlighted words or phrases indicate that additional information is available. You will notice that certain words and phrases are highlighted in green letters, or in white letters on a black background. These are called hypertext terms. If you are using a mouse, double-click on the highlighted word. If you are using a keyboard, press the Tab key to move to the highlighted word, and then press the Enter key. Additional information then appears in a window. How to Use Action Bar Choices Several choices are available for managing information presented in the C/C++Tools Online Language Reference. There are three pull-down menus on the action bar: the Services menu, the Options menu, and the Help menu. The actions that are selectable from the Services menu operate on the active window currently displayed on the screen. These actions include the following: Bookmark Allows you to set a placeholder so you can retrieve information of interest to you. When you place a bookmark on a topic, it is added to a list of bookmarks you have previously set. You can view the list, and you can remove one or all bookmarks from the list. If you have not set any bookmarks, the list is empty. To set a bookmark, do the following: 1. Select a topic from the Contents. 2. When that topic appears, choose the Bookmark option from the Services pull-down. 3. If you want to change the name used for the bookmark, type the new name in the field. 4. Click on the Place radio button (or press the Up or Down Arrow key to select it). 5. Click on OK (or select it and press Enter). The bookmark is then added to the bookmark list. Search Allows you to find occurrences of a word or phrase in the current topic, selected topics, or all topics. You can specify a word or phrase to be searched. You can also limit the search to a set of topics by first marking the topics in the Contents list. To search for a word or phrase in all topics, do the following: 1. Choose the Search option from the Services pull-down. 2. Type the word or words to be searched for. 3. Click on All sections (or press the Up or Down Arrow keys to select it). 4. Click on Search (or select it and press Enter) to begin the search. 5. The list of topics where the word or phrase appears is displayed. Print Allows you to print one or more topics. You can also print a set of topics by first marking the topics in the Contents list. To print the document Contents list, do the following: 1. Choose Print from the Services pull-down. 2. Click on Contents (or press the Up or Down Arrow key to select it). 3. Click on Print (or select it and press Enter). 4. The Contents list is printed on your printer. Copy Allows you to copy a topic that you are viewing to the System Clipboard or to a file that you can edit. This is particularly useful for copying syntax definitions and program samples into the application that you are developing. You can copy a topic that you are viewing in two ways: o Copy copies the topic that you are viewing into the System Clipboard. If you are using a Presentation Manager* (PM) editor (for example, the Enhanced Editor) that copies or cuts (or both) to the System Clipboard, and pastes to the System Clipboard, you can easily add the copied information to your program source module. o Copy to file copies the topic that you are viewing into a temporary file named TEXT.TMP. You can later edit that file by using any editor. TEXT.TMP is placed in the directory where your viewable document resides. To copy a topic, do the following: 1. Expand the Contents list and select a topic. 2. When the topic appears, choose Copy to file from the Services pull-down. 3. The system puts the text pertaining to that topic into the temporary file TEXT.TMP. For information on any of the choices in the Services pull-down, highlight the choice and press the F1 key. The actions that are selectable from the Options menu allow you to change the way your Contents list is displayed. To expand the Contents and show all levels for all topics, choose Expand all from the Options pull-down. You can also press the Ctrl and * keys together. For information on any of the choices in the Options pull-down, highlight the choice and press the F1 key. The actions that are selectable from the Help menu allow you to select different types of help information. You can also press the F1 key for help information about the Information Presentation Facility (IPF). ═══ Related Information ═══ o Copyright o Edition Notice o Notices o Trademarks and Service Marks ═══ 1.1. Copyright ═══ Copyright International Business Machines Corporation, 1993. All rights reserved. Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication, or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM* Corp. ═══ 1.2. Edition Notice ═══ Second Edition, November 1993. This edition applies to Version 2.01 of IBM C/C++ Tools (82G3733, 82G3735, 82G3736) and to all subsequent releases and modifications until otherwise indicated in new editions. This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; any such changes will be reported in subsequent revisions. Requests for publications and for technical information about IBM* products should be made to your IBM Authorized Dealer or your IBM Marketing Representative. When you send information to IBM, you grant IBM a nonexclusive right to use or distribute the information in any ways it believes appropriate without incurring any obligation to you. ═══ 1.3. Notices ═══ References in this publication to IBM* products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program, or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of IBM's intellectual property rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, programs, or services, except those expressly designated by IBM, are the user's responsibility. IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Commercial Relations, IBM Corporation, Purchase, NY 10577. ═══ 1.4. Trademarks and Service Marks ═══ The following terms, denoted by an asterisk (*) in this publication, are trademarks or service marks of IBM Corporation in the United States or other countries: C/2 C Set/2 Common User Access CUA IBM Operating System/2 OS/2 Personal System/2 Presentation Manager PS/2 SAA Systems Application Architecture WorkFrame/2 The following terms, denoted by a double asterisk (**) in this publication, are trademarks of another county as follows: AT&T AT&T Corporation Microsoft Microsoft Corporation Pentium Intel Corporation ═══ IBM Trademark ═══ Trademark of the IBM Corporation. ═══ Non-IBM Trademarks ═══ AT&T is a trademark of AT&T Corporation. Microsoft is a trademark of Microsoft Corporation. Pentium is a trademark of the Intel Corporation. ═══ signed/unsigned types ═══ The signed and unsigned types can be used with either a character (char) or an integer (int, short, long). The unsigned prefix indicates that the value of the object is be a nonnegative value. For more information on conversions between signed and unsigned types, see Conversion from Signed Integer Types and Conversion from Unsigned Integer Types ═══ \ Character ═══ The backslash can appear in string literals or comments as a punctuator. A backslash followed by a single character in C code indicates an escape sequence. A backslash by itself at the end of a line of C code is a continuation character. Escape Sequences provides help on escape sequences and the continuation character. ═══ ( ) ═══ Parentheses are used to group expressions to force a particular order of evaluation. A parenthesized expression usually contains one or more operators and operands (variables or constants), and is often part of an assignment expression. For example, ((x + y) * g) is a parenthesized expression. Parentheses are also used in function calls to group the argument list for the function. The opening parenthesis appears directly after the function name, and may be followed by any number of arguments (or no arguments), followed by the closing parenthesis and a semicolon. For example, fgets(line, 100, stream); is a function call. For help on parenthesized expressions, see Parenthesized Expression ( ). For help on function calls, see Function Call ( ). ═══ + ═══ The plus (+) sign can be used as a unary operator to maintain the value of an operand, for example, +quality. The unary plus sign is the opposite of the unary minus (-) sign, which negates the value of an operand, for example, -quality. The plus sign can also be used as a binary operator in an arithmetic expression to represent the addition operation. For example, x + y indicates that the variables x and y are to be added together. For more information on the unary plus operator, see Unary Plus +. For more information on the addition operator, see Addition +. ═══ - ═══ The minus (-) sign can be used as a unary operator to negate the value of an operand, for example -quality. It can also be used as a binary operator in an arithmetic expression to represent the subtraction operation. For example, x - y indicates that the variable y is to be subtracted from the variable x. For more information on the unary minus operator, see Unary Minus -. For more information on the subtraction operator, see Subtraction -. ═══ & ═══ The ampersand (&) sign can be used as a unary operator to indicate the address of its operand. For example, &anyvar represents the address of the variable anyvar. The ampersand can also be used as a binary operator to represent the bitwise AND operation. For example, in the expression x & y, the corresponding bits of the x and y values are compared to see if the bits are both 1. A double ampersand (&&) is the logical AND operator. which indicate For example, in the expression x && y, the values of x and y are checked to see if both are nonzero values. For more information on the address operator, see Address &. For more information on the bitwise AND operator, see Bitwise AND &. For more information on the logical AND operator, see Logical AND &&. ═══ * ═══ The asterisk (*) can be used as a unary operator to indicate indirection. For example, int *anyvar; declares anyvar as a pointer to int, that points to the value of *anyvar. The asterisk can also be used as a binary operator in an arithmetic expression to represent the multiplication operation. For example, x * y indicates that the variable x is to be multiplied by y. For more information on the indirection operator, see Indirection *. For more information on the multiplication operator, see Multiplication *. ═══ % ═══ The percent (%) sign can be used simply to indicate percentage in a string literal. For example, "More than 50% agree". The percent sign is also used as part of the format specifier for the printf and scanf functions. For example, in the statement printf("The value is %d", anyint); the integer value of anyint is printed in the place of the %d specifier. The percent sign can also be used as a binary operator to represent the modulus (or remainder) operation. For example, the expression x % y indicates that x is divided by y, and the result of the expression is the remainder of the division. For more information on string literals, see Strings. For more information on format specifiers, see -- Reference printf not found -- or -- Reference scanf not found --.. For more information on the remainder operator, see Remainder %. ═══ : ═══ The colon (:) is used to indicate the end of a label and separate it from the following statement. For example, in the expression anylabl: x = y;, anylabl is a label that could be part of a switch statement or the target of a goto statement. The colon is also used in bit-field declarations to separate the identifier of the bit field and the storage it is given. For example, in the structure struct { unsigned x : 4 unsigned y : 1 } the bit fields x and y are assigned 4 bits and 1 bit of storage, respectively. The colon can also be used as part of the compound conditional expression (?:) to separate the two action expressions. For example, in the expression x = (y < z) ? y : z;, if y is less than z, the value of y is assigned to x; if y is not less than z, the value of z is assigned to x. For more information on labels, see Labels. For more information on bit fields, see the section Declaring and Using Bit Fields under Structures. For more information on the compound conditional expression, see Conditional Expression ? :. ═══ ? ═══ The question mark (?) is used for both trigraphs (three characters starting with ??) and as the first part of the operator for the conditional expression. For more information on the compound conditional expression, see Conditional Expression ? :. ═══ , ═══ The comma (,) can be used to separate items such as parameters in a function call. The comma is also used in the comma expression to separate two operands. For example, in the expression x = (y++, z * 4);, the left operand is evaluated then discarded, and the value of the right operand is assigned to x. For more information on the comma expression, see Comma Expression ,. ═══ ; ═══ The semicolon (;) is used to indicate the end of a C expression, for example, int x = 4;. The semicolon can also be used by itself as a null statement to show a nonexistent action. For more information on expressions, see Expression. For more information on null statements, see Null Statement. ═══ 2. Introduction to C ═══ This section introduces you to the C programming language and shows you how to structure C language source programs. Implementation-defined behavior is any action that is not defined by the standards but by the implementing compiler and library. Appendix A in the IBM C/C++ Tools: Programming Guide for a description of the C/C++ Tools implementation-defined behavior. Undefined behavior is any action, by the compiler and library on an erroneous program, that does not result in any expected manner. You should not write any programs to rely on such behavior. Unspecified behavior is any other action by the compiler and library that is not defined. This section includes the following topics: o Overview of the C Language o C Source Programs o C Source Files o Program Execution o Scope in C o Program Linkage o Storage Duration o Name Spaces Related Information o Introduction to C++ ═══ 2.1. Overview of the C Language ═══ C is a programming language designed for a wide variety of programming tasks. It is used for system-level code, text processing, graphics, and in many other application areas. The C language contains a concise set of statements, with functionality added through its library. This division enables C to be both flexible and efficient. An additional benefit is that the language is highly consistent across different systems. The C library contains functions for input and output, mathematics, exception handling, string and character manipulation, dynamic memory management, as well as date and time manipulation. Use of this library helps to maintain program portability, because the underlying implementation details for the various operations need not concern the programmer. C supports numerous data types, including characters, integers, floating-point numbers and pointers - each in a variety of forms. In addition, C also supports arrays, structures (records), unions, and enumerations. Related Information o C and C++ Language Elements o Functions o Types o Introduction to C++ ═══ 2.2. C Source Programs ═══ A C source program is a collection of one or more directives, declarations, and statements contained in one or more source files. Statements specify the action to be performed. Directives instruct the C preprocessor to act on the text of the program. Declarations establish names and define characteristics such as scope, data type and linkage. Definitions are declarations that allocate storage for data objects or define a body for functions. An object definition allocates storage and may optionally initialize the object. A function definition precedes the function body. The function body is a compound statement that can contain declarations and statements that define what the function does. The function definition declares the function name, its parameters, and the data type of the value it returns. The order and scope of declarations affect how you can use variables and functions in statements. In particular, an identifier can be used only after it is declared. A program must contain at least one function definition. If the program contains only one function definition, the function must be called main. If the program contains more than one function definition, only one of the functions can be called main. The main function is the first function called when a program is run. Source for a Simple C Program Related Information o C Source Files o Overview of the C Language o C++ Programs ═══ Source for a Simple C Program ═══ /************************************************************************ * This is the source code of a simple C program: * ************************************************************************/ #include /* standard library header which contains I/O function declarations such as printf used below */ #include /* standard library header which contains math function declarations such as cos used below */ #define NUM 46.0 /* Preprocessor directive */ double x = 45.0; /* External variable definitions */ double y = NUM; int main(void) /* Function definition for main function */ { double z; /* Internal variable */ double w; /* definitions */ z = cos(x); /* cos is declared in math.h as double cos(double arg) */ w = cos(y); printf ("cosine of x is %lf\n", z); /* Print cosine of x */ printf ("cosine of y is %lf\n", w); /* Print cosine of y */ } /************************************************************************ * This source program defines main and declares a reference to the function cos. The program defines the global variables x and y, initializes them, and declares two local variables z and w. * ************************************************************************/ ═══ 2.3. C Source Files ═══ A C source file is the collection of text files that contains all of a C source program. It can include any of the functions that the program needs. To create an executable object module, you compile the separate source files individually and then link them as one program. With the #include directive, you can combine source files into larger source files. A source file contains any combination of directives, declarations, and definitions. You can split items such as function definitions and large data structures between text files, but you cannot split them between compiled files. Before the source file is compiled, the preprocessor filters out preprocessor directives that may change the files. As a result of the preprocessing stage, preprocessor directives are completed, macros are expanded, and a source file is created containing C statements, completed directives, declarations, and definitions. It is sometimes useful to place variable definitions in one source file and declare references to those variables in any source files that use them. This procedure makes definitions easy to find and change, if necessary. You can also organize constants and macros into separate files and include them into source files as required. Directives in a source file apply to that source file and its included files only. Each directive applies only to the part of the file following the directive. Example of C Source Files Related Information o C Source Programs o Overview of the C Language o Declarations and Definitions o Language Statements o Functions o Preprocessor Directives o C++ Programs ═══ Example of C Source Files ═══ /************************************************************************ * The following example is a C program in two source files. The main and max functions are in separate files. The execution of the program begins with the main function. Source file 1 * ************************************************************************/ /************************************************************************ * Source file 1 - main function * ************************************************************************/ #define ONE 1 #define TWO 2 #define THREE 3 extern int max(int, int); /* Function declaration */ int main(int argc, char * argv[]) /* Function definition */ { int u, w, x, y, z; u = 5; z = 2; w = max(u, ONE); x = max(w,TWO); y = max(x,THREE); z = max(y,z); } /************************************************************************ * Source file 2 * ************************************************************************/ /************************************************************************ * Source file 2 - max function * ************************************************************************/ int max (int a,int b) /* Function definition */ { if ( a > b ) return (a); else return (b); } /************************************************************************ * The first source file declares the function max, but does not define it. This is a forward declaration, a reference to the function in source file 2. Four statements in main are function calls of max. The lines beginning with a number sign (#) are preprocessor directives that direct the preprocessor to replace the identifiers ONE, TWO, and THREE with the digits 1, 2, and 3. The directives do not apply to the second source file. The second source file contains the function definition for max, which is called four times in main. After you compile the source files, you can link and run them as a single program. /************************************************************************ * ═══ 2.4. Program Execution ═══ Every program must have a function called main and usually contains other functions. The main function is the starting point for running a program. The statements within the main function are executed sequentially. There may be calls to other functions. A program usually stops running at the end of the main function, although it can stop at other points in the program. You can make your program more modular by creating separate functions to perform a specific task or set of tasks. The main function calls these functions to perform the tasks. Whenever a function call is made, the statements are executed sequentially starting with the first statement in the function. The function returns control to the calling function at the return statement or at the end of the function. You can declare any function to have parameters. When functions are called, they receive values for their parameters from the arguments passed by the calling functions. You can declare parameters for the main function so you can pass values to main from the command line. The command line that starts the program can pass such values as described in main. Related Information o Functions o main o Calling Functions and Passing Arguments o C Source Files o Overview of the C Language o C++ Programs ═══ 2.5. Scope in C ═══ An identifier becomes visible with its declaration. The region where an identifier is visible is referred to as the identifier's scope. The four kinds of scope are: o Block o Function o File o Function prototype The scope of an identifier is determined by where the identifier is declared. See Identifiers for more information on identifiers. In the following example, the variable x, which is defined on line 1, is different from the x defined on line 2. The variable defined on line 2 has function prototype scope and is visible only up to the closing parenthesis of the prototype declaration. Visibility of the variable x defined on line 2 resumes after the end of the prototype declaration. 1 int x = 4; /* variable x defined with file scope */ 2 long myfunc(int x, long y); /* variable x has function */ 3 /* prototype scope */ 4 int main(void) 5 { 6 /* . . . */ 7 } Functions with static storage class are visible only in the source file in which they are defined. All other functions can be globally visible. Example of Scope Related Information o Block o Labels o goto o Functions o static Storage Class Specifier o C Source Files o Scope in C++ ═══ Block Scope ═══ The identifier's declaration is located inside a block. A block starts with an opening brace ({) and ends with a closing brace (}). An identifier with block scope is visible from the point where it is declared to the closing brace that ends the block. You can nest block visibility. A block nested inside a block can contain declarations that redeclare variables declared in the outer block. The new declaration of the variable applies to the inner block. The original declaration is restored when program control returns to the outer block. A variable from the outer block is visible inside inner blocks that do not redefine the variable. ═══ Function Scope ═══ The only identifier with function scope is a label name. A label is implicitly declared by its appearance in the program text. A goto statement transfers control to the label specified on the goto statement. The label is visible to any goto statement that appears in the same function as the label. ═══ File Scope ═══ The identifier's declaration appears outside of any block. It is visible from the point where it is declared to the end of the source file. If source files are included by #include preprocessor directives, those files are considered to be part of the source and the identifier will be visible to all included files that appear after the declaration of the identifier. The identifier can be declared again as a block scope variable. The new declaration replaces the file-scope declaration until the end of the block. ═══ Function Prototype Scope ═══ The identifier's declaration appears within the list of parameters in a function prototype. It is visible from the point where it is declared to the closing parenthesis of the prototype declaration. ═══ Example of Scope ═══ /************************************************************************ * The following program illustrates blocks, nesting, and scope. The example shows two kinds of scope: file and block. Assuming that you defined the function printf elsewhere, the main function prints the values 1, 2, 3, 0, 3, 2, 1 on separate lines. Each instance of i represents a different variable. * ************************************************************************/ int i = 1; /* i defined at file scope */ int main(int argc, char * argv[]) ┌────── { │ │ printf("%d\n", i); /* Prints 1 */ │ │ ┌──── { │ │ int i = 2, j = 3; /* i and j defined at │ │ block scope */ │ │ printf("%d\n%d\n", i, j); /* Prints 2, 3 */ │ │ │ │ ┌── { │ │ │ int i = 0; /* i is redefined in a nested block */ │ │ │ /* previous definitions of i are hidden */ │ │ │ printf("%d\n%d\n", i, j); /* Prints 0, 3 */ │ │ └── } │ │ │ │ printf("%d\n", i); /* Prints 2 */ │ │ │ └──── } │ │ printf("%d\n", i); /* Prints 1 */ │ └────── } ═══ 2.6. Program Linkage ═══ The association, or lack of association, between two identical identifiers is known as linkage. The kind of linkage that an identifier has depends on the way that it is declared. A file scope identifier has one of the following kinds of linkage: Internal Identical identifiers within a single source file refer to the same data object. External Identical identifiers in separately compiled files refer to the same data object. No linkage Each identical identifier refers to a unique object. Note: Program linkage is not the same as a function calling convention, which is also commonly referred to as linkage. While it is related to program linkage, a calling convention concerns itself with linkage specifications and the use of certain keywords. This section discusses only program linkage. Function calling conventions are described in the IBM C/C++ Tools: Programming Guide. Special C++ Considerations: o Linkage specifications are used to link to non-C++ declarations. o When the C++ compiler compiles a program, it encodes all function names and certain other identifiers to include type and scope information. This encoding process is called mangling, and the mangled names are used in the object files and final executable file. Tools that use these files must use the mangled names and not the original names used in the source code. C/C++ Tools provides two methods of converting mangled names to the original source code names, demangling functions and the CPPFILT utility. The demangling functions are described in the appendix on Mapping in the IBM C/C++ Tools: Programming Guide and in the header file. The CPPFILT utility is described in the online C/C++ Tools Compiler Utilities Reference. Related Information o Internal Linkage o External Linkage o No Linkage o Scope in C o Declarations and Definitions ═══ 2.6.1. Internal Linkage ═══ The following kinds of identifiers have internal linkage: o Identifiers with file or block scope that have the keyword static in their declarations. Functions with static storage class are visible only in the source file in which you define them. o Inline functions. o Identifiers declared at file scope with the specifier const and not explicitly declared extern. A variable that has static storage class can be defined within a block or outside of a function. If the definition occurs within a block, the variable has internal linkage and is only visible within the block after its declaration is seen. If the definition occurs outside of a function, the variable has internal linkage and is available from the point where it is defined to the end of the current source file. A class name that has no static members or noninline member functions, and that has not been used in the declaration of an object or function or class is local to its translation unit. If the declaration of an identifier has the keyword extern and if a previous declaration of the identifier is visible at file scope, the identifier has the same linkage as the first declaration. Related Information o Program Linkage o External Linkage o No Linkage o Inline Functions o Storage Class Specifiers ═══ 2.6.2. External Linkage ═══ The following kinds of identifiers have external linkage: o Identifiers with file or block scope that have the keyword extern in their declarations. If a previous declaration of the identifier is visible at file scope, the identifier has the same linkage as the first declaration. For example, a variable or function that is first declared with the keyword static and later declared with the keyword extern has internal linkage. o Function identifiers declared without storage-class specifiers. o Object identifiers that have file scope declared without a storage-class specified. Storage is allocated for such object identifiers. o Static class members and noninline member functions. Identifiers declared with the keyword extern can be defined in other translation units. Related Information o Program Linkage o Internal Linkage o No Linkage o Storage Class Specifiers ═══ 2.6.3. No Linkage ═══ The following kinds of identifiers have no linkage: o Identifiers that do not represent an object or a function, including labels, enumerators, typedef names, type names, and template names o Identifiers that represent a function argument o Identifiers declared inside a block without the keyword extern Related Information o Program Linkage o Internal Linkage o External Linkage o extern Storage Class Specifier o Identifiers ═══ 2.7. Storage Duration ═══ Storage duration determines how long storage for an object exists. An object has either static storage duration or automatic storage class depending on its declaration. An object with static storage duration has storage allocated for it at initialization which remains available until program termination. All objects with file scope have static storage duration. An object has static storage duration if it has internal or external linkage or if it contains the keyword static. All other objects have automatic storage. Storage for an object with automatic storage class is allocated and removed according to the scope of the identifier. For example, storage for an object declared at block scope is allocated when the identifier is declared and removed when the closing brace of the block is reached. An object has automatic storage duration if it is declared with no linkage and does not have the static storage class specifier. Related Information o Storage Class Specifiers o Scope in C o Program Linkage ═══ 2.8. Name Spaces ═══ In any C program, identifiers refer to functions, data objects, labels, tags, parameters, macros, and typedefs. C allows the same identifier to be used for more than one class of identifier, as long as you follow the rules outlined in this section. Name spaces are categories used to group similar types of identifiers. You must assign unique names within each name space to avoid conflict. The same identifier can be used to declare different objects as long as each identifier is unique within its name space. The context of an identifier within a program lets the compiler resolve its name space without ambiguity. Identifiers in the same name space can be redefined within enclosed program blocks as described in Scope in C. Within each of the following four name spaces, the identifiers must be unique. o These identifiers must be unique within a single scope: - Function names - Variable names - Names of function parameters - Enumeration constants - typedef names o Tags of these types must be unique within a single scope: - Enumerations - Structures - Unions o Members of structures and unions must be unique within a single structure or union. o Statement labels have function scope and must be unique within a function. Structure tags, structure members, and variable names are in three different name spaces; no conflict occurs among the three items named student in the following example: struct student /* structure tag */ { char student[20]; /* structure member */ int class; int id; } student; /* structure variable */ Each occurrence of student is interpreted by its context in the program. For example, when student appears after the keyword struct, it is a structure tag. When student appears after either of the member selection operators . or ->, the name refers to the structure member. (See Expressions and Operators to find out how to refer to members of union or structure variables.) In other contexts, the identifier student refers to the structure variable. Related Information o Types o Expressions and Operators o Scope in C o Identifiers ═══ 3. Introduction to C++ ═══ This section describes the C++ language implemented by the &prods., briefly summarizes the differences between C and C++, and discusses the principles of object-oriented programming. C++ is an object-oriented language based on the C programming language. It can be viewed as a superset of C. Almost all of the features and constructs available in C are also available in C++. However, C++ is more than just an extension of C. Its additional features support the programming style known as object-oriented programming. Several features that are already available in C, such as input and output may be implemented differently in C++. In C++ you may use the conventional C input and output routines or you may use object oriented input and output by using the I/O Stream class library. C++ was developed by Bjarne Stroustrup of AT&T** It was originally based on the definition of the C language stated in The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie. This C language definition is commonly called K&R C. Since the introduction of C++, the American National Standard for Information Systems Standard C language definition (commonly called ANSI C) has been developed. The ANSI C definition specifies many of the features that K&R left unspecified. Features of ANSI C have been incorporated into the current definition of C++, and some parts of the ANSI C definition have been motivated by C++. While there is currently no C++ standard comparable to the ANSI C definition, an ANSI committee is working on such a definition. The current draft of the Working Paper for Draft Proposed American National Standard for Information Systems - Programming Language C++ (X3J16/92-00091, September 17, 1992) is the base document for the ongoing standardization of C++. The C++ compiler adheres to this version of the ANSI working paper. The following topics are discussed in this section: o C++ Support for Object-Oriented Programming o C++ Programs o Scope in C++ o Simple C++ Input and Output o Linkage Specifications - Linking to non-C++ Programs Related Information o Introduction to C ═══ 3.1. C++ Support for Object-Oriented Programming ═══ Object-oriented programming is based on the concepts of data abstraction, inheritance, and polymorphism. Unlike procedural programming, it concentrates on the data objects that are involved in a problem and how they are manipulated, not on how something is accomplished. Based on the foundation of data abstraction, object-oriented programming allows you to reuse existing code more efficiently and increase your productivity. o Data Abstraction o Encapsulation o Inheritance o Dynamic Binding and Polymorphism o Other Features of C++ Related Information o C++ Classes o Member Access o Inheritance Overview o Derivation o Introduction to C++ ═══ Data Abstraction ═══ Data abstraction provides the foundation for object-oriented programming. In addition to providing fundamental data types, object-oriented programming languages allow users to define their own data types, called user-defined or abstract data types. In the C programming language, related data items can be organized into structures. These structures can then be manipulated as units of data. In addition to providing this type of data structure, object-oriented programming languages allow you to implement a set of operations that can be applied to the data elements. The data elements and the set of operations applicable to the data elements together form the abstract data type. To support data abstraction, a programming language must provide a construct that can be used to encapsulate the data elements and operations that make up an abstract data type. In C++, this construct is called a class. An instance of a class is called an object. Classes are composed of data elements called data members and member functions that define the operations that can be carried out on the data members. ═══ Encapsulation ═══ Another key feature of object-oriented programming is encapsulation. Encapsulation means a class can hide the details of: o The representation of its data members o The implementation of the operations that can be performed on these data members Application programs manipulate objects of a class using a clearly defined interface. As long as this interface does not change, you can change the implementation of a class without having to change the application programs that use the class. Encapsulation provides the following advantages: o Users of a class do not have to deal with unnecessary implementation details. o Programs are easier to debug and maintain. o Permitted alterations are clearly specified. In C++, encapsulation is accomplished by specifying the level of access for each member of a class. Both the data members and member functions of a class can be declared public, protected, or private depending on the kind of access required. Note: C++ encapsulation is not a true security mechanism. The implementation does not guard against undesired or unauthorized modifications of a class declaration intended to increase access to restricted class members. ═══ Inheritance ═══ Inheritance lets you reuse existing code and data structures in new applications. In C++, inheritance is implemented through class derivation. You can extend a library of existing classes by adding data elements and operations to existing classes to form derived classes. A derived class has all the members of its parent or base class, as well as extensions that can provide additional features. When you create a new derived class, you only have to write the code for the additional features. The existing features of the base class are already available. A base class can have more than one class derived from it. In addition, a derived class can serve as a base class for other derived classes in a hierarchy. Typically, a derived class is more specialized than its base class. A derived class can inherit data members and member functions from more than one base class. Inheritance from more than one base class is called multiple inheritance. ═══ Dynamic Binding and Polymorphism ═══ Another key concept that allows you to write generic programs is dynamic or late binding. Dynamic binding affects the derivation process and allows each user-defined class in an inheritance hierarchy to have a different implementation of a particular function. Application programs can then apply that function to an object without needing to know the specifics of the class that the object belongs to. In C++, dynamic binding hides the differences between a group of classes in an inheritance hierarchy from the application program. At run time, the system determines the specific class of the object and invokes the appropriate function implementation for that class. ═══ Other Features of C++ ═══ C++ provides several other powerful extensions to the C programming language. Among these are: o Constructors and destructors, which are used to create, initialize and destroy class objects o Overloaded functions and operators, which provide static or compile-time binding of function calls o Inline functions, which make programs more efficient o Pass-by-reference calls, which allow a function to modify its arguments in the calling function o Template functions and classes, which allow user-defined families of classes and compile-time binding of functions o Exception handling, which provides transfer of control and recovery from errors and other exceptional circumstances ═══ 3.2. C++ Programs ═══ C++ programs contain many of the same programming statements and constructs as C programs: o C++ has the same fundamental types (built-in data types) as C. o Like ANSI C, C++ allows you to declare new type names by using the typedef construct. These new type names are not new types. o In general, the scope and storage class rules for C also apply in C++. o C and C++ have the same set of arithmetic and logical operators. A C++ name can identify any of the following: o an object o a function o a set of functions o an enumerator o a type o a class member o a template o a value o a label A declaration introduces a name into a program and can define an area of storage associated with that name. An expression performs some computational action and is composed of operations and operands. An expression ending with a ; (semicolon) is called a statement. A statement is the smallest independent computational unit. Functions are composed of groups of one or more statements. A C++ program is composed of one or more functions. These functions can all reside in a single file or can be placed in different files that are linked to each other. In C++, a program must have one and only one function called main(). Source for a Simple C++ Program Related Information o C++ Support for Object-Oriented Programming o Introduction to C o C Source Files o C Source Programs ═══ Source for a Simple C++ Program ═══ /************************************************************************ * The following is a simple C++ program containing declarations, expressions, statements, and two functions: * ************************************************************************/ #include // contains definition of abs() extern double multiplier, common_ratio; // variable declarations double geo_series(double a, double r) // function definition { if (r == 1) // if statement return -1.0; // return statement else if (abs(r) < 1.0) // else if statement return (a / (1 - r)); // statement containing // expression else return -2.0; } void main() // program execution begins here { double sum; // variable definition sum = geo_series(multiplier, common_ratio); // function call // .. } ═══ 3.3. Scope in C++ ═══ The area of the code where an identifier is visible is referred to as the scope of the identifier. The four kinds of scope are: o Local o Function o File o Class The scope of a name is determined by the location of the name's declaration. A type name first declared in a function return type has file scope. A type name first declared in a function argument list has local scope. A function name that is first declared as a friend of a class is in the first nonclass scope that encloses the class. If the friend function is a member of another class, it has the scope of that class. The scope of a class name first declared as a friend of a class is the first nonclass enclosing scope. Related Information o Scope in C o Friend Scope o Scope of Class Names o Member Scope ═══ Local Scope ═══ A name has local scope if it is declared in a block. A name with local scope can be used in that block and in blocks enclosed within that block, but the name must be declared before it is used. When the block is exited, the names declared in the block are no longer available. Formal argument names for a function have the scope of the outermost block of that function. If a local variable is a class object with a destructor, the destructor is called when control passes out of the block in which the class object was constructed. When one block is nested inside another, the variables from the outer block are usually visible in the nested block. However, if an outer block variable is redefined in a nested block, the new declaration is in effect in the inner block. The original declaration is restored when program control returns to the outer block. This is called block visibility. ═══ Function Scope ═══ The only type of identifier with function scope is a label name. A label is implicitly declared by its appearance in the program text and is visible throughout the function that declares it. ═══ File Scope ═══ A name has file scope if its declaration appears outside of all blocks and classes. A name with file scope is visible from the point where it is declared to the end of the source file. The name is also made accessible for the initialization of global variables. If a name is declared extern, it is also visible, at linkage time, in all object files being linked. Global names are names declared with file scope. ═══ Class Scope ═══ The name of a class member has class scope and can only be used in the following cases: o In a member function of that class o In a member function of a class derived from that class o After the . (dot) operator applied to an instance of that class o After the . (dot) operator applied to an instance of a class derived from that class o After the -> (arrow) operator applied to a pointer to an instance of that class o After the -> (arrow) operator applied to a pointer to an instance of a class derived from that class o After the :: (scope resolution) operator applied to the name of a class o After the :: (scope resolution) operator applied to a class derived from that class. For more information on class scope, see Scope of Class Names ═══ 3.4. Simple C++ Input and Output ═══ Like C, the C++ language has no built-in input and output facilities. Instead, input and output facilities for C++ are provided by the I/O Stream Library. For compatibility with C, C++ also supports the standard I/O functions of C. The I/O Stream Library supports a set of I/O operations, written in the C++ language, for the built-in types. You can extend these facilities to provide input and output functions for user-defined data types. For a complete description of the I/O Stream Library, see the Standard Class Library Guide. There are four standard predefined I/O stream objects that you can use to perform standard I/O: o cout o cin o cerr o clog You can use these in conjunction with the overloaded << (insertion or output) and >> (extraction or input) operators. To use these streams and operators, you must include the header file iostream.h. The following example prints Hello World! to standard output: #include void main() { cout << "Hello World!" << endl; } The manipulator endl acts as a newline character, causing any output following it to be directed to the next line. Because it also causes any buffered output to be flushed, endl is preferred over \n to end lines. Related Information o Introduction to C++ o Introduction to C o Overloading Operators ═══ cout ═══ The cout stream is associated with standard output. You can use the output operator in conjunction with cout to direct a value to standard output. Successive output operators are concatenated when applied to cout. The following example prints out three strings in a row and produces the same result as the previous example, printing Hello World! to standard output. #include void main() { cout << "Hello " << "World" << "!" << endl; } The output operator is defined to accept arguments of any of the fundamental data types, as well as pointers, references, and array types. You can also overload the output operator to define output for your own class types. ═══ cerr and clog ═══ The cerr and clog streams direct output to standard error. cerr provides unbuffered output, while clog provides buffered output. The following example checks for a division by zero condition. If one occurs, a message is sent to standard error. #include void main(void) { double val1, val2; cout << "Divide Two Values" << endl; cout << "Enter two numeric values: " << endl; cin >> val1 >> val2; if (val2 == 0 ) { cerr << "The second value must be non-zero" << endl; } else cout << "The answer is " << val1 / val2 << endl; } ═══ cin ═══ The cin class object is associated with standard input. You can use the input operator in conjunction with cin to read a value from standard input. White space (including blanks, tabs, and new lines) is disregarded by the input operator. For example: #include main() { double val1, val2; cout << "Enter two numeric values:" << endl; cin >> val1 >> val2; cout << "The first value entered is " << val1 << " and the second value is " << val2 << "." << endl; } If the values 1.2 and 3.4 are entered through standard input, the above program prints the following to standard output: Enter two numeric values: 1.2 3.4 The first value entered is 1.2 and the second value is 3.4. Any white space entered between the two numeric values is disregarded by the input operator. The input operator is defined to accept arguments of any of the fundamental data types, as well as pointers, references and array types. You can also overload the input operator to define input for your own class types. ═══ 3.5. Linkage Specifications - Linking to non-C++ Programs ═══ You can link C++ code to code produced by other compilers by using a linkage specification. The syntax is: >>──extern──string-literal──┬─declaration─────────────┬──>< │ ┌───────────────┐ │ │  │ │ └─{───┬─────────────┬┴──}─┘ └─declaration─┘ The string-literal is used to specify the linkage associated with a particular function. For example: extern "C" int printf(const char*,...); void main() { printf("hello\n"); } Here the string-literal, "C", tells the compiler that the routine printf(char*,...) has C linkage. Note that string literals used in linkage specifications are not case sensitive. The valid values for string-literal include: "C++" Default "C" C type linkage If the value of string-literal is not recognized, C type linkage is used. For more information on linkage specifications, see Chapter 13, "Calling Conventions" in the IBM C/C++ Tools: Programming Guide. Related Information o Introduction to C++ o Introduction to C ═══ 4. C and C++ Language Elements ═══ This section describes the following basic elements of the C and C++ programming languages. o Character Set o Trigraphs o Escape Sequences o Comments o Identifiers o Keywords o Constants ═══ 4.1. Character Set ═══ The following lists the basic character set that must be available at both compile and run time: o The uppercase and lowercase letters of the English alphabet o The decimal digits 0 through 9 o The following graphic characters: ! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] _ { } ~ o The caret (^) character o The split vertical bar (|) character o The space character o The control characters representing horizontal tab, vertical tab, form feed, and end of string. When the language level is set to extended or compatible (with the /Se or /Sc option), the C++ character set also allows the dollar ($) character to be used in identifiers. Uppercase and lowercase letters are treated as distinct characters. For the keyboards that do not support the entire character set, you can use trigraphs as alternative symbols to represent some characters. Related Information o Trigraphs o Source Code Options ═══ 4.2. Trigraphs ═══ Some characters from the C character set are not available in all environments. You can enter these characters into a C source program using a sequence of three characters called a trigraph. The trigraph sequences are: ┌──────────┬──────────────┐ │ "??=" │ "#" │ ├──────────┼──────────────┤ │ "??(" │ "[" │ ├──────────┼──────────────┤ │ "??)" │ "]" │ ├──────────┼──────────────┤ │ "??<" │ "{" │ ├──────────┼──────────────┤ │ "??>" │ "}" │ ├──────────┼──────────────┤ │ "??/" │ "\" │ ├──────────┼──────────────┤ │ "??'" │ "^" │ ├──────────┼──────────────┤ │ "??!" │ "|" │ ├──────────┼──────────────┤ │ "??-" │ "~" │ └──────────┴──────────────┘ The preprocessor replaces trigraph sequences with the corresponding single-character representation. Related Information o Character Set ═══ 4.3. Escape Sequences ═══ An escape sequence contains a backslash (\) symbol followed by one of the escape sequence characters or \ or followed by an octal or hexadecimal number. A hexadecimal escape sequence contains an x followed by one or more hexadecimal digits (0-9, A-F, a-f). An octal escape sequence contains one or more octal digits (0-7). The C language escape sequences and the characters they represent are: ┌────────────┬──────────────────────┐ │ ESCAPE │ CHARACTER REPRES- │ │ SEQUENCE │ ENTED │ ├────────────┼──────────────────────┤ │ "\a" │ Alert (bell) │ ├────────────┼──────────────────────┤ │ "\b" │ Backspace │ ├────────────┼──────────────────────┤ │ "\f" │ Form feed (new page) │ ├────────────┼──────────────────────┤ │ "\n" │ New-line │ ├────────────┼──────────────────────┤ │ "\r" │ Carriage return │ ├────────────┼──────────────────────┤ │ "\t" │ Horizontal tab │ ├────────────┼──────────────────────┤ │ "\v" │ Vertical tab │ ├────────────┼──────────────────────┤ │ "\'" │ Single quotation │ │ │ mark │ ├────────────┼──────────────────────┤ │ "\"" │ Double quotation │ │ │ mark │ ├────────────┼──────────────────────┤ │ "\?" │ Question mark │ ├────────────┼──────────────────────┤ │ "\\" │ Backslash │ ├────────────┴──────────────────────┤ │ NOTE: "\" - The line continua- │ │ tion sequence (\ followed by a │ │ new-line character) which is used │ │ in C language character strings │ │ to indicate that the current line │ │ continues on the next line, is │ │ not an escape sequence. │ └───────────────────────────────────┘ The value of an escape sequence represents the member of the character set used at run time. For example, on a system that uses the ASCII character codes, the letter V is represented by the escape sequence \x56. You can place an escape sequence in a character constant or in a string constant. If an escape sequence is not recognized, the compiler uses the character following the backslash and a message is issued. Note that this behavior is implementation-defined. In string and character sequences, when you want the backslash to represent itself (rather than the beginning of an escape sequence), you must use a \\ backslash escape sequence. Related Information o Character Constants o Strings ═══ 4.4. Comments ═══ Comments begin with the /* characters, end with the */ characters, and may span more than one line. You can place comments anywhere the language allows white space. White space includes space, tab, form feed, and new-line characters. If the /Ss compiler option is in effect when you compile your program, double slashes (//) will also specify the beginning of a comment. The comment ends at the next new line character. C++ also permits double-slash comments as part of the language definition. Note: The /* or */ characters found in a character constant or string literal do not start or end comments. You cannot nest comments. Each comment ends at the first occurrence of */. Multibyte characters can also be included within a comment. Related Information o /Ss ═══ 4.5. Identifiers ═══ Identifiers provide names for functions, data objects, labels, tags, parameters, macros, and typedefs. There is no limit for the number of characters in an identifier. However, only the first several characters of identifiers may be significant. The following table shows the character lengths of identifiers that are recognized by the C/C++ Tools compiler. For SAA* C compilers, the minimal length of identifiers is 100 characters. Some compilers may allow longer identifiers. Identifier Minimum Number of Significant Characters Static data objects 255 characters Static function names 255 characters External data objects 255 characters External function names 255 characters For identifiers, uppercase and lowercase letters are viewed as different symbols. Thus, PROFIT and profit represent different data objects. At the extended and compatible language levels, C++ identifiers can contain the $ character. Note: By default, the LINK386 linker is not case sensitive. To preserve case sensitivity, use the /NOI linker option. If you use icc to invoke the linker, this option is specified for you. For complete portability, never use different case representations to refer to the same object. Avoid creating identifiers that begin with an underscore (_) for function names and variable names. Identifiers beginning with an underscore, are reserved. Identifiers used for C library functions that begin with two underscores or an underscore followed by a capital letter, are reserved. Although the names of system calls and library functions are not reserved words if you do not include the appropriate header files, avoid using them as identifiers. Duplication of a predefined name can lead to confusion for the maintainers of your code and can cause errors at link time or run time. If you include a library in a program, be aware of the function names in that library to avoid name duplications. You should always include the appropriate header files when using standard library functions. Related Information o Name Spaces o Introduction to C o #include ═══ 4.6. Keywords ═══ The C language reserves some identifiers, known as keywords, for special use. You cannot use these words as identifiers. Although you can use them for macro names, it is not recommended that you do so. Only the exact spellings of the words as specified below are reserved. For example, auto is reserved but AUTO is not. The following table lists the keywords common to both the C and C++ languages. These keywords are also included in the ANSI C language definition: ┌──────────────────────────────────────────────────────────────────────────────┐ │ Keywords Common to C and C++ │ ├───────────────────┬───────────────────┬───────────────────┬──────────────────┤ │ auto │ double │ int │ struct │ │ break │ else │ long │ switch │ │ case │ enum │ register │ typedef │ │ char │ extern │ return │ union │ │ const │ float │ short │ unsigned │ │ continue │ for │ signed │ void │ │ default │ goto │ sizeof │ volatile │ │ do │ if │ static │ while │ └───────────────────┴───────────────────┴───────────────────┴──────────────────┘ The keyword _Packed is also reserved for C programs. _Packed is an extension to the ANSI C standard, and is not supported by C++. The C++ language also reserves the following keywords: ┌──────────────────────────────────────────────────────────────────────────────┐ │ C++ Keywords │ ├───────────────────┬───────────────────┬───────────────────┬──────────────────┤ │ asm │ friend │ private │ this │ │ catch │ inline │ protected │ throw │ │ class │ new │ public │ try │ │ delete │ operator │ template │ virtual │ └───────────────────┴───────────────────┴───────────────────┴──────────────────┘ The C/C++ Tools compiler also reserves the following keywords. They are considered to be C/C++ Tools extensions to the existing language standards. Except for the keywords _Far32 and _Inline, the following keywords are supported in both C and C++. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Additional C/C++ Tools Keywords │ ├───────────────────┬───────────────────┬───────────────────┬──────────────────┤ │ _Cdecl │ _Far32 │ _Inline │ _Pascal │ │ _Export │ _Fastcall │ _Optlink │ _Seg16 │ │ _Far16 │ │ │ _System │ └───────────────────┴───────────────────┴───────────────────┴──────────────────┘ ═══ 4.7. Constants ═══ The C language contains the following types of constants: o Integer Constants o Floating-Point Constants o Character Constants o Strings o Enumeration Constants A constant is data with a value that does not change during the execution of a program. The value of any constant must be in the range of representable values for its type. For more information on data types, see Types. ═══ 4.7.1. Integer Constants ═══ Integer constants can be either decimal, octal, or hexadecimal values. The following diagram lists these forms: >>──┬─decimal_constant─────┬──┬──────────────┬──>< ├─octal_constant───────┤ ├─┬─l─┬──┬───┬─┤ └─hexadecimal_constant─┘ │ └─L─┘ ├─u─┤ │ │ └─U─┘ │ └─┬─u─┬──┬───┬─┘ └─U─┘ ├─l─┤ └─L─┘ The data type of an integer constant is determined by the constant's value. The following table describes the integer constant and a list of possible data types for that constant. The smallest data type in the list that can contain the constant value will be associated with the constant. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Data Types for Integer Constants │ ├────────────────────────┬─────────────────────────────────────────────────────┤ │ CONSTANT │ DATA TYPE │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ unsuffixed decimal │ "int, long int, unsigned long int" │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ unsuffixed octal │ "int, unsigned int, long int, unsigned long int" │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ unsuffixed hexadecimal │ "int, unsigned int, long int, unsigned long int" │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ suffixed by "u" or "U" │ "unsigned int, unsigned long int" │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ suffixed by "l" or "L" │ "long int, unsigned long int" │ ├────────────────────────┼─────────────────────────────────────────────────────┤ │ suffixed by both "u" │ "unsigned long int" │ │ or "U", │ │ │ and "l" or "L" │ │ └────────────────────────┴─────────────────────────────────────────────────────┘ A plus (+) or minus (-) symbol can precede the constant. It is treated as a unary operator rather than as part of the constant value. Related Information o Decimal Constants o Octal Constants o Hexadecimal Constants o Integers ═══ 4.7.2. Decimal Constants ═══ A decimal constant contains any of the digits 0 through 9. The first digit cannot be 0. Integer constants beginning with the digit 0 are interpreted as an octal constant, rather than as a decimal constant. The following are examples of decimal constants: 485976 433132211 20 5 Related Information o Integer Constants o Octal Constants o Hexadecimal Constants o Integers ═══ 4.7.3. Hexadecimal Constants ═══ A hexadecimal constant begins with the 0 digit followed by either an x or X. After the 0x, you can place any combination of the digits 0 through 9 and the letters a through f or A through F. When used to represent a hexadecimal constant, the lowercase letters are equivalent to their corresponding uppercase letters. The following are examples of hexadecimal constants: 0x3b24 0XF96 0x21 0x3AA 0X29b 0X4bD Related Information o Integer Constants o Decimal Constants o Octal Constants o Integers ═══ 4.7.4. Octal Constants ═══ An octal constant begins with the digit 0 and contains any of the digits 0 through 7. 0 0125 034673 03245 Related Information o Integer Constants o Decimal Constants o Hexadecimal Constants o Integers ═══ 4.7.5. Floating-Point Constants ═══ A floating-point constant consists of an integral part, a decimal point, a fractional part, an exponent part, and an optional suffix. Both the integral and fractional parts are made up of decimal digits. You can omit either the integral part or the fractional part, but not both. You can omit either the decimal point or the exponent part (but not both). The exponent part consists of e or E, followed optionally by a sign and a decimal number. The floating-point constant 8.45e+3 evaluates as follows: 8.45 * (10 ** 3) = 8450.0 The representation of a floating-point number on a system is unspecified. If a floating-point constant is too large or too small, the result is undefined. The suffix f or F indicates a type of float, and the suffix l or L indicates a type of long double. If a suffix is not specified, the floating-point constant has a type double. A plus (+) or minus (-) symbol can precede a floating-point constant. However, it is not part of the constant; it is interpreted as a unary operator. The following are examples of floating-point constants: ┌────────────────────────┬────────────────────────┐ │ FLOATING-POINT CON- │ VALUE │ │ STANT │ │ ├────────────────────────┼────────────────────────┤ │ "5.3876e4" │ "53,876" │ ├────────────────────────┼────────────────────────┤ │ "4e-11" │ "0.00000000004" │ ├────────────────────────┼────────────────────────┤ │ "1e+5" │ "100,000" │ ├────────────────────────┼────────────────────────┤ │ "7.321E-3" │ "0.007321" │ ├────────────────────────┼────────────────────────┤ │ "3.2E+4" │ "32,000" │ ├────────────────────────┼────────────────────────┤ │ "0.5e-6" │ "0.0000005" │ ├────────────────────────┼────────────────────────┤ │ "0.45" │ "0.45" │ ├────────────────────────┼────────────────────────┤ │ "6.e10" │ "60,000,000,000" │ └────────────────────────┴────────────────────────┘ Related Information o Floating-Point Variables ═══ 4.7.6. Character Constants ═══ A character constant contains a sequence of characters or escape sequences enclosed in single quotation mark symbols. At least one character or escape sequence must appear in the character constant. It can contain any character from the C character set, excluding the single quotation mark, backslash and new-line symbols. The prefix L indicates a wide character constant. A character constant must appear on a single source line. The value of a character constant containing a single character is the numeric representation of the character in the character set used at run time. The value of a wide character constant containing a single multibyte character is the code for that character, as defined by the mbtowc function. If the character constant contains more than one character, the last 4 bytes represent the character constant. A character constant has type int. A wide character constant is represented by a double-byte character of type wchar_t, as defined in the include file. Multibyte characters represent character sets that go beyond the single byte character set. Each multibyte character can contain up to 4 bytes. Restrictions To represent the single quotation symbol, backslash, and new-line characters, you must use the respective escape sequence. For more information on escape sequences, see Escape Sequences. The following are examples of character constants: 'a' '\'' '0' '(' 'x' '\n' '7' '\117' 'C' Related Information o Strings o Escape Sequences o Integers ═══ 4.7.7. Strings ═══ A string constant or literal contains a sequence of characters or escape sequences enclosed in double quotation mark symbols. A null (\0) character is appended to each string. For a wide character string (a string prefixed by the letter L), the value 0 of type wchar_t is appended. By convention, programs recognize the end of a string by finding the null character. If you want to continue a string on the next line, use the line continuation sequence (\ symbol immediately followed by a new-line character). Another way to continue a string is to have two or more consecutive strings. Adjacent string literals are concatenated to produce a single string. (The null character of the first string will no longer exist after the concatenation.) You cannot concatenate a wide string constant with a character string constant. Multiple spaces contained within a string constant are retained. A character string constant has type array of char and static storage duration. A wide character constant has type array of wchar_t and static storage duration. You can use the escape sequence \n to represent a new-line character as part of the string. You can use the escape sequence \\ to represent a backslash character as part of the string. You can represent the single quotation mark symbol by itself ', but you use the escape sequence \" to represent the double quotation mark symbol. You should be careful when modifying string literals because the resulting behavior depends on whether your strings are stored in writable static. See #pragma for more information on #pragma strings that can be used to specify whether your string literals are readonly or writable. String literals are writable by default. The following are examples of string literals: char titles[ ] = "Bach's \"Jesu, Joy of Man's Desiring\""; char *mail_addr = "Last Name First Name MI Street Address \ City Province Postal code "; char *temp_string = "abc" "def" "ghi"; /* *temp = "abcdefghi\0" */ Related Information o Character Constants o Escape Sequences o Characters o Arrays o #pragma o #pragma strings ═══ 4.7.8. Enumeration Constants ═══ When you define an enumeration data type, you specify a set of identifiers that the data type represents. Each identifier in this set is an enumeration constant. In C, each enumeration constant has an integer value. In C++, each enumeration constant has a value that can be promoted to a signed or unsigned integer value. You can use an enumeration constant anywhere an integer constant is allowed, or for C++, anywhere a value of the enumeration type is allowed. The value of the constant is determined in the following way: 1. An equal sign (=) and a constant expression after the enumeration constant gives an explicit value to the constant. The identifier represents the value of the constant expression. 2. If no explicit value is assigned, the leftmost constant in the list receives the value zero (0). 3. Identifiers with no explicitly assigned values receive the integer value that is one greater than the value represented by the previous identifier. In C, an enumeration constant has type int. In C++, an enumeration constant has a distinct type that does not have to be integral. Enumeration constants can be promoted to a signed or unsigned integral constant when used in an expression. The following data type declarations list oats, wheat, barley, corn, and rice as enumeration constants. The number under each constant shows the integer value. enum grain { oats, wheat, barley, corn, rice }; /* 0 1 2 3 4 */ enum grain { oats=1, wheat, barley, corn, rice }; /* 1 2 3 4 5 */ enum grain { oats, wheat=10, barley, corn=20, rice }; /* 0 10 11 20 21 */ It is possible to associate the same integer with two different enumeration constants. For example, the following definition is valid. The identifiers suspend and hold have the same integer value. enum status { run, delete=5, suspend, resume, hold=6 }; Related Information o Enumerations o Integers ═══ 5. Declarations and Definitions ═══ A declaration establishes the names and characteristics of data objects and functions used in a program. A definition is a declaration that allocates storage for data objects or specifies the body for a function. The following table shows examples of declarations and definitions. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Examples of Declarations and Definitions │ ├───────────────────────────────┬──────────────────────────────────────────────┤ │ DECLARATIONS │ DECLARATIONS AND DEFINITIONS │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ "extern double pi;" │ "double pi = 3.14159265;" │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ "float square(float x);" │ "float square(float x) { return x*x; }" │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ "struct payroll;" │ struct payroll { │ │ │ char *name; │ │ │ float salary; │ │ │ } employee; │ └───────────────────────────────┴──────────────────────────────────────────────┘ The declaration for a data object can include the following components: o Storage class, described in Storage Class Specifiers o Type, described in Types o Qualifier and Declarator, described in Declarators o Initializer, described in Initializers. Function declarations are described in Functions. Declarations determine the following properties of data objects and their identifiers: o Scope, which describes the visibility of an identifier in a block or source file. For a complete description of scope, see Scope in C. o Storage duration, which describes when the system allocates and frees storage for a data object. o Linkage, which describes the association between two identical identifiers. See Program Linkage for more information. o Type, which describes the kind of data the object is to represent. Syntax of a Data Declaration Related Information o Block Scope Data Declarations o File Scope Data Declarations o Storage Class Specifiers o Types o Declarators o Initializers ═══ Syntax of a Data Declaration ═══ All data declarations have the form: ┌────────────,─────────────┐  │ ─┬─type_specifier────────────────┬──declarator──┬────────────┬┴──;── │ │ │ │ ├─────────────┬──┬──────────────┤ └─initializer┘ │ │ │ │ └storage_class┘ └type_specifier┘ ═══ 5.1. Block Scope Data Declarations ═══ A block scope data declaration can only be placed at the beginning of a block. It describes a variable and makes that variable accessible to the current block. All block scope declarations that do not have the extern storage class specifier are definitions and allocate storage for that object. You can define a data object with block scope with any of the storage class specifiers described in Storage Class Specifiers. If you do not specify a storage class specifier in a block-scope data declaration, the default storage class specifier auto is used. If you specify a storage class specifier, you can omit the type specifier. If you omit the type specifier, all variables declared in that declaration will have the type int. Initialization You cannot initialize a variable that is declared in a block scope data declaration and has the extern storage class specifier. The types of variables you can initialize and the values that uninitialized variables receive vary for each storage class specifier. Storage Declarations with the auto or register storage class specifier result in automatic storage duration. Declarations with the extern or static storage class specifier result in static storage duration. Related Information o auto Storage Class Specifier o register Storage Class Specifier o extern Storage Class Specifier o static Storage Class Specifier o Declarations and Definitions o Declarators o Initializers o Types ═══ 5.2. File Scope Data Declarations ═══ A file scope data declaration appears outside any block. It describes a variable and makes that variable accessible to all functions that are in the same file and whose definitions appear after the declaration. A file scope data definition is a data declaration at file scope that also causes the system to allocate storage for that variable. All objects whose identifiers are declared at file scope have static storage duration. You can use a file scope data declaration to declare variables that you want several functions to access. The only storage class specifiers you can place in a file scope data declaration are static and extern. If you specify static, all variables defined in it have internal linkage. If you do not specify static, all variables defined in it have external linkage. If you specify the storage class static or extern, you can omit the type specifier. If you omit the type specifier, all variables defined in that declaration receive the type int. Initialization You can initialize any object with file scope. If you do not initialize a file scope variable, its initial value is zero of the appropriate type. If you do initialize it, the initializer must be described by a constant expression, or it must reduce to the address of a previously declared variable at file scope, possibly modified by a constant expression. Initialization of all variables at file scope takes place before the main function begins execution. Storage All objects with file scope data declarations have static storage duration. The system allocates memory for all file scope variables when the program begins execution and frees it when the program is finished executing. Related Information o extern Storage Class Specifier o static Storage Class Specifier o Declarations and Definitions o Declarators o Initializers o Types ═══ 5.3. Objects ═══ An object is a region of storage that contains a value or group of values. Each value can be accessed using its identifier or a more complex expression that refers to the object. In addition, each object has a unique data type. Both the identifier and data type of an object are established in the object declaration. The data type of an object determines the initial storage allocation for that object and the interpretation of the values during subsequent access. It is also used in any type-checking operations. C++ has built-in, or standard, data types and user-defined data types. Standard data types include signed and unsigned integers, floating-point numbers, and characters. User-defined types include enumerations, structures, unions, and classes. An instance of a class type is commonly called a class object. The individual class members are also called objects. The set of all member objects comprises a class object. Related Information o Types o C++ Classes o Declarations and Definitions ═══ 5.4. Storage Class Specifiers ═══ The storage class specifier used within the declaration determines the following: o Whether the object has internal, external, or no linkage. o Whether the object has static class (storage for the object is maintained throughout program execution) or automatic class (storage for the object is maintained only during the execution of the block in which the identifier of the object is defined) storage duration. o Whether the object is to be stored in memory or in a register, if available. o Whether the object receives the default initial value 0 or an indeterminate default initial value. For a function, the storage class specifier determines the function's linkage. The C/C++ Tools compiler implements an additional storage class specifier for functions, inline. The _Inline and inline specifiers determine whether the function code will be inlined or called. Note that _Inline and inline are ignored if the /Oi- compiler option is specified. The following sections describe the storage class specifiers: o auto Storage Class Specifier o register Storage Class Specifier o extern Storage Class Specifier o static Storage Class Specifier o Inline Specifiers Related Information o Program Linkage o Inline Functions o Declarations and Definitions o Inline Specifiers o /Oi option ═══ 5.4.1. auto Storage Class Specifier ═══ The auto storage class specifier enables you to define a variable with automatic storage; its use and storage is restricted to the current block. The storage class keyword auto is optional in a data declaration and forbidden in a parameter declaration. A variable having the auto storage class specifier must be declared within a block. It cannot be used for file scope declarations. You can initialize any auto variable except parameters. If you do not initialize an automatic object, its value is undefined. If you provide an initial value, the expression representing the initial value can be any valid C or C++ expression. For aggregates or unions, the initial value must be a valid constant expression. The object is then set to that initial value each time the program block that contains the object's definition is entered. Note: If you use the goto statement to jump into the middle of a block, automatic variables within that block are not initialized. Objects with the auto storage class specifier have automatic storage duration. Each time a block is entered, storage for auto objects defined in that block is made available. When the block is exited, the objects are no longer available for use. If an auto object is defined within a function that is recursively invoked, memory is allocated for the object at each invocation of the block. Declaring variables with the auto storage class specifier can decrease the amount of memory required for program execution, because auto variables require storage only while they actually are needed. Generally, it is not a good idea to use automatic storage for large objects because of the time needed by the operating system to allocate or deallocate large amounts of storage. Examples of auto Storage Class Related Information o Storage Class Specifiers o register Storage Class Specifier o Block Scope Data Declarations o Function Declarator o Address & ═══ Examples of auto Storage Class ═══ /************************************************************************ * The following program shows the scope and initialization of auto variables. The function main defines two variables, each named auto_var. The first definition occurs on line 8. The second definition occurs in a nested block on line 11. While the nested block is executed, only the auto_var created by the second definition is available. During the rest of the program, only the auto_var created by the first definition is available. * ************************************************************************/ 1 /* program to illustrate auto variables */ 2 3 #include 4 5 int main(void) 6 { 7 void call_func(int passed_var); 8 auto int auto_var = 1; /* first definition of auto_var */ 9 10 { 11 int auto_var = 2; /* second definition of auto_var */ 12 printf("inner auto_var = %d\n", auto_var); 13 } 14 call_func(auto_var); 15 printf("outer auto_var = %d\n", auto_var); 16 } 17 18 void call_func(int passed_var) 19 { 20 printf("passed_var = %d\n", passed_var); 21 passed_var = 3; 22 printf("passed_var = %d\n", passed_var); 23 } /************************************************************************ * This program produces the following output: inner auto_var = 2 passed_var = 1 passed_var = 3 outer auto_var = 1 The following example uses an array that has the storage class auto to pass a character string to the function sort. The C language views an array name that appears without subscripts (for example, string, instead of string[0]) as a pointer. Thus, sort receives the address of the character string, rather than the contents of the array. The address enables sort to change the values of the elements in the array. * ************************************************************************/ /* Sorted string program */ #include int main(void) { void sort(char *array, int n); char string[75]; int length; printf("Enter letters:\n"); scanf("%74s", string); length = strlen(string); sort(string,length); printf("The sorted string is: %s\n", string); } void sort(char *array, int n) { int gap, i, j, temp; for (gap = n / 2; gap > 0; gap /= 2) for (i = gap; i < n; i++) for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap) { temp = array[j]; array[j] = array[j + gap]; array[j + gap] = temp; } } /********************************************************************************** * When the program is run, interaction with the program could produce: Output Enter letters: Input zyfab Output The sorted string is: abfyz * ************************************************************************/ ═══ 5.4.2. extern Storage Class Specifier ═══ The extern storage class specifier enables you to declare objects and functions that several source files can use. All object declarations that occur outside a function and that do not contain a storage class specifier declare identifiers with external linkage. All function definitions that do not specify a storage class define functions with external linkage. You can distinguish an extern declaration from an extern definition by the presence of the keyword extern and the absence of an initial value. If the keyword extern is absent or if there is an initial value, the declaration is also a definition; otherwise, it is just a declaration. An extern definition can appear only outside a function definition. Only one declaration of the variable without the keyword extern can be used, and that declaration is the definition of the storage for the variable. If a declaration for an identifier already exists at file scope, any extern declaration of the same identifier found within a block refers to that same object. If no other declaration for the identifier exists at file scope, the identifier has external linkage. An extern declaration cannot appear in class scope. An extern declaration can appear outside a function or at the beginning of a block. If the declaration describes a function or appears outside a function and describes an object with external linkage, the keyword extern is optional. You can initialize any object with the extern storage class specifier at file scope. You can initialize an extern object with an initializer that must either: o Appear as part of the definition and the initial value must be described by a constant expression. o Reduce to the address of a previously declared object with static storage duration. This object may be modified by a constant expression. If you do not initialize an extern variable, its initial value is zero of the appropriate type. Initialization of an extern object is completed by the start of program execution. extern objects have static storage duration. Memory is allocated for extern objects before the main function begins execution. When the program finishes executing, the storage is freed. Examples of extern Storage Class Related Information o Storage Class Specifiers o File Scope Data Declarations o Function Definition o Function Declarator o Constant Expression ═══ Examples of extern Storage Class ═══ /************************************************************************ * The following program shows the linkage of extern objects and functions. The extern object total is declared on line 12 of File 1 and on line 11 of File 2. The definition of the external object total appears in File 3. The extern function tally is defined in File 2. The function tally can be placed in the same file as main or in a different file. Because main precedes these definitions and main uses both total and tally, main declares tally on line 11 and total on line 12. File 1 ************************************************************************/ 1 /************************************************************** 2 ** This program receives the price of an item, adds the ** 3 ** tax, and prints the total cost of the item. ** 5 **************************************************************/ 6 7 #include 8 9 int main(void) 10 { /* begin main */ 11 void tally(void); /* declaration of function tally */ 12 extern float total; /* first declaration of total */ 13 14 printf("Enter the purchase amount: \n"); 15 tally(); 16 printf("\nWith tax, the total is: %.2f\n", total); 17 } /* end main */ /************************************************************************ * File 2 * ************************************************************************/ 1 /************************************************************** 2 ** This file defines the function tally ** 3 **************************************************************/ 4 #include 5 6 #define tax_rate 0.05 7 8 void tally(void) 9 { /* begin tally */ 10 float tax; 11 extern float total; /* second declaration of total */ 12 13 scanf("%f", &total); 14 tax = tax_rate * total; 15 total += tax; 16 } /* end tally */ /************************************************************************ * File 3 * ************************************************************************/ 1 float total; /************************************************************************ * The following program shows extern variables used by two functions. Because both functions main and sort can access and change the values of the extern variables string and length, main does not have to pass parameters to sort. * ************************************************************************/ /* Sorted string program */ #include char string[75]; int length; int main(void) { void sort(void); printf("Enter letters:\n"); scanf("%s", string); length = strlen(string); sort(); printf("The sorted string is: %s\n", string); } void sort(void) { int gap, i, j, temp; for (gap = length / 2; gap > 0; gap /= 2) for (i = gap; i < length; i++) for (j = i - gap; j >= 0 && string[j] > string[j + gap]; j -= gap) { temp = string[j]; string[j] = string[j + gap]; string[j + gap] = temp; } } /************************************************************************ * When this program is run, interaction with the previous program could produce: Output Enter letters: Input zyfab Output The sorted string is: abfyz The following program shows a static variable var1 which is defined at file scope and then declared with the storage class specifier extern. The second declaration refers to the first definition of var1 and so it has internal linkage. static int var1; . . . extern int var1; * ************************************************************************/ ═══ 5.4.3. register Storage Class Specifier ═══ The register storage class specifier indicates to the compiler within a file scope data definition or a parameter declaration that the object being described will be heavily used (such as a loop control variable). Note: Because the C/C++ Tools compiler optimizes register use, it does not respect the register keyword. The storage class keyword register is required in a data definition and in a parameter declaration that describes an object having the register storage class. An object having the register storage class specifier must be defined within a block or declared as a parameter to a function. You can initialize any register object except parameters. If you do not initialize an automatic object, its value is undefined. If you provide an initial value, the expression representing the initial value can be any valid C or C++ expression. For aggregates or unions, the initial value must be a valid constant expression. The variable is then set to that initial value each time the program block that contains the object's definition is entered. Objects with the register storage class specifier have automatic storage duration. Each time a block is entered, storage for register objects defined in that block are made available. When the block is exited, the objects are no longer available for use. If a register object is defined within a function that is recursively invoked, the system allocates memory for the variable at each invocation of the block. The register storage class specifier indicates that the object is heavily used and indicates to the compiler that the value of the object should reside in a machine register. Not all register variables are actually placed in registers. If the compiler does not allocate a machine register for a register object, the object is treated as having the storage class specifier auto. Because of the limited size and number of registers available on most systems, few variables can be stored in registers at the same time. Using register definitions for variables that are heavily used may make your object files smaller and make them run faster. In object code, a reference to a register can require less code and time than a reference to memory. Restrictions o In C programs, you cannot apply the & (address) operator to register variables. However, C++ allows you to take the address of an object with the register storage class. For example: register i; int* b = &i; // valid in C++, but not in C o You cannot use the register storage class specifier on file scope data declarations. Related Information o Storage Class Specifiers o auto Storage Class Specifier o Block Scope Data Declarations o Address & ═══ 5.4.4. static Storage Class Specifier ═══ The static storage class specifier enables you to define objects with static storage duration and internal linkage, or to define functions with internal linkage. An object having the static storage class specifier can be defined within a block or at file scope. If the definition occurs within a block, the object has no linkage. If the definition occurs at file scope, the object has internal linkage. You can initialize any static object. If you do not provide an initial value, the object receives the value of zeros of the appropriate type. If you initialize a static object, the initializer must be described by a constant expression or must reduce to the address of a previously declared extern or static object, possibly modified by a constant expression. Objects with the static storage class specifier have static storage duration. The storage for a static variable is made available when the program begins execution. When the program finishes executing, the memory is freed. You cannot declare a static function at block scope. You can use static variables when you need an object that retains its value from one execution of a block to the next execution of that block. Using the static storage class specifier keeps the system from reinitializing the object each time the block in which the object is defined is executed. C++ Consideration: If a local static variable is a class object with constructors and destructors, the object will be constructed when control passes through its definition for the first time. If a local class object is created by a constructor, its destructor is called immediately before or as part of the calls of the atexit function. Examples of static Storage Class Related Information o Storage Class Specifiers o Block Scope Data Declarations o File Scope Data Declarations o Function Definition o Function Declarator ═══ Examples of static Storage Class ═══ /************************************************************************ * The following program shows the linkage of static identifiers at file scope. This program uses two different external static identifiers named stat_var. The first definition occurs in file 1. The second definition occurs in file 2. The main function references the object defined in file 1. The var_print function references the object defined in file 2: File 1 * ************************************************************************/ /************************************************************************ ** Program to illustrate file scope static variables ** ************************************************************************/ #include extern void var_print(void); static stat_var = 1; int main(void) { printf("file1 stat_var = %d\n", stat_var); var_print(); printf("FILE1 stat_var = %d\n", stat_var); } /************************************************************************ * File 2 * ************************************************************************/ #include static int stat_var = 2; void var_print(void) { printf("file2 stat_var = %d\n", stat_var); } /************************************************************************ * The preceding program produces the following output: file1 stat_var = 1 file2 stat_var = 2 FILE1 stat_var = 1 The following program shows the linkage of static identifiers with block scope. The function test defines the static variable stat_var. stat_var retains its storage throughout the program, even though test is the only function that can reference stat_var. * ************************************************************************/ /************************************************************************ ** Program to illustrate block scope static variables ** ************************************************************************/ #include int main(void) { void test(void); int counter; for (counter = 1; counter <= 4; ++counter) test(); } void test(void) { static int stat_var = 0; auto int auto_var = 0; stat_var++; auto_var++; printf("stat_var = %d auto_var = %d\n", stat_var, auto_var); } /************************************************************************ * The preceding program produces the following output: stat_var = 1 auto_var = 1 stat_var = 2 auto_var = 1 stat_var = 3 auto_var = 1 stat_var = 4 auto_var = 1 * ************************************************************************/ ═══ 5.4.5. Inline Specifiers ═══ C/C++ Tools provides two keywords, _Inline for C programs and inline for C++ programs, that you can use to specify the user functions you want the compiler to inline. For example: _Inline int catherine(int a); causes catherine to be inlined, meaning that code is generated for the function, rather than a function call. The inline keywords also implicitly declare the function as static. By default, function inlining is turned off, and functions qualified with _Inline or inline are treated simply as static functions. To turn on function inlining, specify the /Oi+ option. If you turn optimization on (/O+), /Oi+ becomes the default. Recursive functions (functions that call themselves) are inlined for the first occurrence only. The call to the function from within itself will not be inlined. You can also use the /Oivalue option to automatically inline all functions smaller than value abstract code units as well as those qualified with _Inline or inline. For best performance, use the inline keywords to choose the functions you want to inline rather than using automatic inlining. When inlining is turned on, the following functions are also considered candidates to be inlined: o C++ member functions that are defined in class declarations. o For C programs only, small functions of static storage class that are called only once. Note: If you plan to debug your code (specifying /Ti+), you should turn inlining off. You should also be aware that profiling hooks are not generated for inlined functions. For more information on function inlining, see the Programming Guide. Related Information o static Storage Class Specifier o Storage Class Specifiers o Inline Functions o Inline Member Functions o /Oi ═══ 5.5. Declarators ═══ A declarator designates a data object or function. Declarators appear in all data definitions and declarations and in some type definitions. In a declarator, you can specify the type of an object to be an array, a pointer, or a reference. You can specify that the return type of a function is a pointer or a reference. You can also perform initialization in a declarator. Syntax of a Declarator You cannot declare or define a volatile or const function. A simple declarator consists of an identifier, which names a data object. For example, the following block scope data declaration uses initial as the declarator: auto char initial; The data object initial has the storage class auto and the data type char. You can define or declare an aggregate by using a declarator that contains an identifier, which names the data object, and some combination of symbols and identifiers, which describes the type of data that the object represents. An aggregate is a structure, union, or array. The following declaration uses compute[5] as the declarator: extern long int compute[5]; Examples of Declarators Related Information o volatile and const Qualifiers o _Packed Qualifier o _Seg16 Type Qualifier o _Export Qualifier o Declarations and Definitions o Arrays o Enumerations o Pointers o Structures o Unions ═══ Syntax of a Declarator ═══ A declarator has the form: ─┬─┬─────┬─┬─────identifier─────┬──┬──────────────────────────┬──┬─ │ │┌───┐│ │ │ │ │ │ │ │ ││ └──(──declarator──)──┘ ├──────────(──)────────────┤ │ │ └──*─┴┘ │ ┌──────────────────────┐ │ │ │ │  │ │ │ │ └───subscript_declarator─┴─┘ │ │ │ │ │ ├──────────┬─┬─────┬─┬──identifier─────┬─┬──────────────────────┤ │ │ │┌───┐│ │ │ │ │ └─qualifier┘ │ ││ └(─subdeclarator─)┘ └─subscript_declarator─┘ └──*─┴┘ A qualifier is one of: const, volatile or _Packed. The C/C++ Tools compiler also implements the _Seg16 _Export, and _Inline qualifiers. Note: C++ does not support the _Packed keyword. A declarator can contain a subdeclarator. A subdeclarator has the form: ──┬──────────────────────┬──┬──────identifier───────┬── │ ┌──────────────────┐ │ │ │ │  │ │ └──(──subdeclarator──)──┘ └──┬────────────┬──*─┴─┘ │ │ ├──volatile──┤ │ │ └───const────┘ ──┬────────────────────────┬── │ │ └─ subscript_declarator──┘ A subscript declarator describes the number of dimensions in an array and the number of elements in each dimension. A subscript declarator has the form: ──[──┬───────────────────────┬──]─┬───────────────────────────────┬─ │ │ │ ┌───────────────────────────┐ │ └──constant_expression──┘ │  │ │ └───[──constant_expression──]─┴─┘ ═══ 5.5.1. volatile and const Qualifiers ═══ The volatile qualifier maintains the intent of the original expression with respect to stores and fetches of volatile objects. The volatile qualifier is useful for data objects having values that may be changed in ways unknown to your program (such as the system clock). Objects referenced by multiple threads or by signal handlers should also be qualified as volatile. Portions of an expression that reference volatile objects are not to be changed or removed. The const qualifier explicitly declares a data object as a data item that cannot be changed. Its value is set at initialization. You cannot use const data objects in expressions requiring a modifiable lvalue. For example, a const data object cannot appear on the left-hand side of an assignment statement. For a volatile or const pointer, you must place the keyword between the * and the identifier. For example: int * volatile x; /* x is a volatile pointer to an int */ int * const y = &z; /* y is a const pointer to the int variable z */ For a pointer to a volatile or const data object, you must place the keyword before the type specifier. For example: volatile int *x; /* x is a pointer to a volatile int */ const int *y; /* y is a pointer to a const int */ You can assign a value to the int * const y but not to const int * y. For other types of volatile and const variables, the position of the keyword within the definition (or declaration) is less important. For example: volatile struct omega { int limit; char code; } group; provides the same storage as: struct omega { int limit; char code; } volatile group; In both examples, only the structure variable group receives the volatile qualifier. Similarly, if you specified the const keyword instead of volatile, only the structure variable group receives the const qualifier. The const and volatile qualifiers when applied to a structure, union, or class also apply to the members of the structure, union, or class. Although enumeration, structure, and union variables can receive the volatile or const qualifier, enumeration, structure, and union tags do not carry the volatile or const qualifier. For example, the blue structure does not carry the volatile qualifier: volatile struct whale { int weight; char name[8]; } killer; struct whale blue; The keyword volatile or const cannot separate the keywords enum, struct, and union from their tags. You can declare or define a volatile or const function only if it is a member function. You can define or declare any function to return a pointer to a volatile or const function. You can place more than one qualifier on a declaration but you cannot specify the same qualifier more than once on a declaration. These type qualifiers are only meaningful on expressions that are lvalues. Related Information o Declarators o _Packed Qualifier o _Seg16 Type Qualifier o _Export Qualifier o Types o Structures o Unions o Enumerations o Pointers o Lvalue ═══ 5.5.2. _Packed Qualifier ═══ The _Packed qualifier removes padding between members of structures and unions, whenever possible. However, the storage saved using packed structures and unions may come at the expense of runtime performance. Most machines access data more efficiently if it is aligned on appropriate boundaries. With packed structures and unions, members are generally not aligned on natural boundaries, and the result is that member-accessing operations (using the . and -> operators) are slower. _Packed can only be used with structs or unions. If you use _Packed with other types, an error message is generated and the qualifier has no effect on the declarator it qualifies. Packed and nonpacked structures and unions have different storage layouts. However, a packed structure or union can be assigned to a nonpacked structure or union of the same type, and nonpacked structure or union can be assigned to a packed structure or union. Comparisons between packed and nonpacked structures or unions of the same type are prohibited. If you specify the _Packed qualifier on a structure or union that contains a structure or union as a member, the qualifier is not passed on to the contained structure or union. The C/C++ Tools compiler also lets you pack structures using the #pragma pack directive or the /Sp option. See #pragma for more information on #pragma pack. Note: C++ does not support the _Packed keyword. Use the #pragma directive or compiler option to control the alignment of structures and unions. Related Information o pack o /Sp option o Declarators o volatile and const Qualifiers o _Seg16 Type Qualifier o _Export Qualifier o Types o Structures o Unions ═══ Examples of Declarators ═══ The following table describes some declarators: Example Description int owner owner is an int data object. int *node node is a pointer to an int data object. int names[126] names is an array of 126 int elements. int *action( ) action is a function returning a pointer to an int. volatile int min min is a int that has the volatile int * volatile volume volume is a volatile pointer to an int. volatile int * next next is a pointer to a volatile int volatile int * sequence[5] sequence is an array of five pointers to volatile int objects. extern const volatile int op_system_clock op_system_clock is an extern int that has the volatile attribute. ═══ 5.5.3. _Seg16 Type Qualifier ═══ Because pointers are interpreted differently in 16-bit programs than in 32-bit programs, they cannot be shared between the two types of program. Use the _Seg16 type qualifier when calling 16-bit code to ensure correct mapping of pointers between the different types of code. For example: char * _Seg16 p16; declares p16 to be a segmented pointer that can be addressed by a 16-bit program. The pointer can also be used in a 32-bit program, because the compiler converts it to 32-bit form. The _Seg16 qualifier can only be used with pointers. Note that _Seg16 comes after the asterisk in the declaration, as required by ANSI syntax rules. All pointers shared between 32-bit and 16-bit code must be qualified with _Seg16. These include pointers passed indirectly to 16-bit code, such as pointers in structures and pointers that are referenced by pointers passed directly to 16-bit code. While it is possible to write a program where all the pointers are qualified with _Seg16, it is not recommended. Every time a segmented pointer is used in a 32-bit program, it must be converted to a 32-bit pointer and then back to segmented pointer to be stored. This process will cause a noticeable performance degradation in your program. Pointers that are not shared with 16-bit code and those that are passed by value to 16-bit code (that is, as a parameter to a function) do not need to be qualified with _Seg16. For more information on using _Seg16 and calling 16-bit programs from 32-bit code, see the Programming Guide. Related Information o Pointers o #pragma seg16 o Declarators o volatile and const Qualifiers o _Packed Qualifier o _Export Qualifier ═══ 5.5.4. _Export Qualifier ═══ Use the _Export keyword with a function name to declare that the function is to be exported, that is, made available to other modules. For example: int _Export anthony(float); causes the function anthony to be exported. You can use _Export at any language level. If you also use linkage keywords, you can place _Export either before or after a linkage keyword. For example, both of the following declarations are valid: int _Export _Optlink brian(int); int _Optlink _Export brian(int); The _Export keyword is an alternative to the #pragma export directive. Note that #pragma export allows you to specify both a name and an ordinal number by which the function can be called. If you use _Export, other modules must call the function using its original name. If you use _Export to export your function, you may still need to provide an EXPORTS entry for that function in your module definition (.DEF) file. If your function has any of the following default characteristics o Has shared data o Has no I/O privileges o Is not resident it does not require an EXPORTS entry. If your function has characteristics other than the defaults, the only way you can specify them is with an EXPORTS entry in your .DEF file. Note: To create an import library for the DLL, you must either create it from the DLL itself or provide a .DEF file with an EXPORTS entry for every function, regardless of whether _Export is used. For more information on DLLs and .DEF files, see the Programming Guide. Related Information o #pragma export o Declarators o volatile and const Qualifiers o _Packed Qualifier o _Seg16 Type Qualifier ═══ 5.6. Initializers ═══ An initializer is an optional part of a data declaration that specifies an initial value of a data object. Syntax of an Initializer The initializer consists of the = symbol followed by an initial expression or a braced list of initial expressions separated by commas. The number of initializers should not be more than the number of elements to be initialized. The initial expression evaluates to the first value of the data object. An initializer of the form (expression_list) can be used to initialize C++ classes. For more information on initializing classes, see Initialization by Constructor. To assign a value to a scalar object, use the simple initializer: = expression. For example, the following data definition uses the initializer =3 to set the initial value of group to 3: int group = 3; In C++, you can also use the (expression_list) form to initialize fundamental types. For example, the following two initializations are identical: int group = 3; int group(3); For unions, structures, and aggregate classes (classes with no constructors, base classes, virtual functions, or private or protected members), the set of initial expressions must be enclosed in { } (braces) unless the initializer is a string literal. If the initializer of a character string is a string literal, the { } are optional. Individual expressions must be separated by commas, and groups of expressions can be enclosed in braces and separated by commas. The number of initializers must be less than or equal to the number of objects being initialized. In the following example, only the first eight elements of the array grid are explicitly initialized. The remaining four elements that are not explicitly initialized are initialized as if you explicitly initialized them to zero. static short grid[3] [4] = {0, 0, 0, 1, 0, 0, 1, 1}; The initial values of grid are: Element Value grid[0][0] 0 grid[0][1] 0 grid[0][2] 0 grid[0][3] 1 grid[1][0] 0 grid[1][1] 0 grid[1][2] 1 grid[1][3] 1 grid[2][0] 0 grid[2][1] 0 grid[2][2] 0 grid[2][3] 0 C++ Considerations: o You can initialize variables at file scope with nonconstant expressions. This is not allowed in ANSI C. o If your code jumps over declarations that contain initializations, the compiler generates an error. For example, the following code is not valid in C++: goto skiplabel; // error - jumped over declaration int i = 3; // and initialization of i skiplabel: i = 4; o You can initialize classes in external, static, and automatic definitions. The initializer contains an = (equal sign) followed by a brace-enclosed, comma-separated list of values. You do not need to initialize all members of a class. Initialization considerations for each data type are described in the section for that data type. Related Information o Block Scope Data Declarations o File Scope Data Declarations o Arrays o Characters o Enumerations o Floating-Point Variables o Integers o Pointers o Structures o Unions ═══ Syntax of an Initializer ═══ An initializer has the form: ┌─,──────────┐  │ >>──┬─(───expression─┴─)────────────────────────┬─────────────────────────────>< └─=──┬─expression─────────────────────────┬─┘ │ ┌─,──────────┐ │ │  │ │ └─{──┬───expression─┴───────────┬──}─┘ │ ┌─,────────────────────┐ │ │ │ ┌─,──────────┐ │ │ │   │ │ │ └───{────expression─┴──}─┴─┘ The form (expression) is allowed in C++ only. ═══ 5.7. Types ═══ The fundamental data types for C and C++ are: o Characters o Floating-Point Variables o Integers o void Type o Enumerations From these types, you can derive the following: o Arrays o Pointers o References (C++ only) o Structures o Unions o Functions o Classes (C++ only) o Pointers to Members (C++ only) ═══ 5.7.1. Characters ═══ There are three character data types: char, signed char, and unsigned char. These data types provide enough storage to hold any member of the character set used at run time. For the C/C++ Tools compiler, the size of a char is 8 bits. The default type of char is unsigned char. You can change this default using #pragma chars or the /J compiler option. If it does not matter whether a char data object is signed or unsigned, you can declare the object as having the data type char; otherwise, explicitly declare signed char or unsigned char. C++ Consideration: For the purposes of distinguishing overloaded functions, char in C++ is a distinct type from signed char and unsigned char. When a char (signed or unsigned) is widened to an int, its value is preserved. To declare a data object having a character data type, place a char specifier in the type specifier position of the declaration. The declarator for a simple character declaration is an identifier. You can initialize a simple character with a character constant or with an expression that evaluates to an integer. You can use the char specifier in variable definitions to define such variables as: arrays of characters, pointers to characters, and arrays of pointers to characters. Examples of Character Data Types Related Information o Arrays o Pointers o Character Constants o Assignment Expression o Declarators o Initializers ═══ Examples of Character Data Types ═══ The following example defines the identifier end_of_string as a constant object of type char having the initial value \0 (the null character): const char end_of_string = '\0'; The following example defines the unsigned char variable switches as having the initial value 3: unsigned char switches = 3; The following example defines string_pointer as a pointer to a character: char *string_pointer; The following example defines name as a pointer to a character. After initialization, name points to the first letter in the character string "Johnny": char *name = "Johnny"; The following example defines a one-dimensional array of pointers to characters. The array has three elements. Initially they are a pointer to the string "Venus", a pointer to "Jupiter", and a pointer to "Saturn": static char *planets[ ] = { "Venus", "Jupiter", "Saturn" }; ═══ 5.7.2. Floating-Point Variables ═══ There are three types of floating-point variables: float, double, and long double. The storage size of a float variable is less than or equal to the storage size of a double variable. The storage size of a double variable is less than or equal to the storage size of a long double variable. Thus, the following expression always evaluates to 1 (true): sizeof(float) <= sizeof(double) && sizeof(double) <= sizeof(long double) For the C/C++ Tools compiler, the size of a float is 4 bytes, a double is 8 bytes, and a long double is 16 bytes. To declare a data object having a floating-point type, use the float specifier. The declarator for a simple floating-point declaration is an identifier. You can initialize a simple floating-point variable with a float constant or with a variable or expression that evaluates to an integer or floating-point number. (The storage class of a variable determines how you can initialize the variable.) Examples of Floating-Point Data Types Related Information o Floating-Point Constants o o Assignment Expression o Integers o Declarators o Initializers ═══ Examples of Floating-Point Data Types ═══ The following example defines the identifier pi for an object of type double: double pi; The following example defines the float variable real_number with the initial value 100.55: static float real_number = 100.55; The following example defines the float variable float_var with the initial value 0.0143: float float_var = 1.43e-2; The following example declares the long double variable maximum: extern long double maximum; The following example defines the array table with 20 elements of type double: double table[20]; ═══ 5.7.3. Integers ═══ There are six types of integer variables: o short int, short, signed short, or signed short int o signed int or int (In some cases, no type specifier is needed; see Block Scope Data Declarations and File Scope Data Declarations.) o long int, long, signed long, or signed long int o unsigned short int or unsigned short o unsigned or unsigned int o unsigned long int or unsigned long. C++ Considerations: When the arguments in overloaded functions and overloaded operators are integer types, two integer types that both come from the same group are not treated as distinct types. For example, you cannot overload an int argument against a signed int argument. Overloading and argument matching is described in C++ Overloading. The default integer type for a bit field is unsigned. The storage size of a short type is less than or equal to the storage size of an int variable and the storage size of an int variable is less than or equal to the storage size of a long variable. Thus, the following expression always evaluates to 1 (true): sizeof(short) <= sizeof(int) && sizeof(int) <= sizeof(long) Two sizes for integer data types are provided. Objects having type short are 2 bytes of storage long. Objects having type long are 4 bytes of storage long. An int represents the most efficient data storage size on the system (the word-size of the machine) and receives 4 bytes of storage. The unsigned prefix indicates that the value of the object is a nonnegative integer. Each unsigned type provides the same size storage as its signed equivalent. For example, int reserves the same storage as unsigned int. Because a signed type reserves a sign bit, an unsigned type can hold a larger positive integer than the equivalent signed type. To declare a data object having an integer data type, place an int specifier in the type specifier position of the declaration. The declarator for a simple integer definition or declaration is an identifier. You can initialize a simple integer definition with an integer constant or with an expression that evaluates to a value that can be assigned to an integer. (The storage class of a variable determines how you can initialize the variable.) Examples of Integer Data Types Related Information o Integer Constants o Decimal Constants o Octal Constants o Hexadecimal Constants o Declarators o Initializers ═══ Examples of Integer Data Types ═══ The following example defines the short int variable flag: short int flag; The following example defines the int variable result: int result; The following example defines the unsigned long int variable ss_number as having the initial value 438888834: unsigned long ss_number = 438888834ul; The following example defines the identifier sum for an object of type int. The initial value of sum is the result of the expression a + b: extern int a, b; auto sum = a + b; ═══ 5.7.4. void Type ═══ void is a data type that always represents an empty set of values. The keyword for this type is void. When a function does not return a value, you should use void as the type specifier in the function definition and declaration. An argument list for a function taking no arguments is void. The only object that can be declared with the type specifier void is a pointer. You cannot declare a variable of type void. You can explicitly convert any expression to type void, but the resulting expression can only be used as one of the following: o An expression statement o The left operand of a comma expression o The second or third operand in a conditional expression. Example of void Type Related Information o Cast Expressions o Types o Expressions and Operators ═══ Example of void Type ═══ /************************************************************************ * On line 3 of the following example, the function find_max is declared as having type void. Lines 12 through 23 contain the complete definition of find_max. Note that the use of the sizeof operator in line 9 is a standard method of determining the number of elements in an array. * ************************************************************************/ 1 #include 2 3 /* declaration of function find_max */ 4 extern void find_max(int x[ ], int j); 5 6 int main(void) 7 { 8 static int numbers[ ] = { 99, 54, -102, 89 }; 9 10 find_max(numbers, (sizeof(numbers) / sizeof(numbers[0]))); 11 } 12 void find_max(int x[ ], int j) 13 14 { /* begin definition of function find_max */ 15 int i, temp = x[0]; 16 17 for (i = 1; i < j; i++) 18 { 19 if (x[i] > temp) 20 temp = x[i]; 21 } 22 printf("max number = %d\n", temp); 23 } /* end definition of function find_max */ ═══ 5.7.5. Enumerations ═══ An enumeration data type represents a set of values that you declare. You can define an enumeration data type and all variables that have that enumeration type in one statement, or you can separate the declaration of the enumeration data type from all variable definitions. The identifier associated with the data type (not an object) is a tag. Note: In C, an enumeration must be of type int. This restriction does not apply to C++. In C++, an enumeration has a distinct type that does not have to be integral. Enumeration constants can be promoted to a signed or unsigned integral constant when used in an expression. An enumeration type declaration contains the enum keyword followed by an identifier (the enumeration tag) and a brace-enclosed list of enumerators. Each enumerator is separated by a comma. Syntax of an Enumeration The keyword enum, followed by the identifier, names the data type (like the tag on a struct data type). The list of enumerators provides the data type with a set of values. In C, each enumerator represents an integer value. In C++, each enumerator represents a value that can be converted to an integral value. To conserve space, enumerations may be stored in spaces smaller than that of an int. By default, the type of the enum variable is the size of the smallest integral type that can contain all enumerator values. You can change the default using the /Su option. The identifier in an enumerator is called an enumeration constant. You can use an enumeration constant anywhere a value of the enumeration type can be used. When an enumeration constant is used in an expression, the C/C++ Tools compiler can promote it to a signed or unsigned integral constant to determine its value. The value of an enumeration constant is determined by the following rules: 1. If an = (equal sign) and a constant expression follow the identifier, the identifier represents the value of the constant expression. 2. If the enumerator is the leftmost value in the list, the identifier represents the value 0. 3. Otherwise, the identifier represents the integer value that is one greater than the value represented by the preceding enumerator. Each enumeration constant must be unique within the block or the file where the enumeration data type is defined. In the following example, the declarations of average on line 4 and of poor on line 5 cause compiler error messages: 1 func() 2 { 3 enum score { poor, average, good }; 4 enum rating { below, average, above }; 5 int poor; 6 } Additional information is provided on: o Defining Enumeration Variables o Defining Enumeration Types and Objects o Example Program Using Enumeration Types Examples of Enumeration Types Related Information o Enumeration Constants o Constant Expression o Identifiers o Declarators o Initializers ═══ Syntax of an Enumeration ═══ An enumeration type declaration has the form: ┌──────,─────┐  │ ──enum─────┬──────────────┬──{───enumerator─┴─}──── │ │ └──identifier──┘ An enumerator has the form: ──identifier──┬─────────────────────────────┬── │ │ └──=────constant_expression───┘ ═══ Examples of Enumeration Types ═══ The following example declares the enumeration tag status: enum status { run, create, delete=5, suspend }; The data type status represents the following values: Enumeration Integer Constant Representation run 0 create 1 delete 5 suspend 6 ═══ 5.7.5.1. Defining Enumeration Variables ═══ An enumeration variable definition contains a storage class specifier (optional), a type specifier, a declarator, and an initializer (optional). The type specifier contains the keyword enum followed by the name of the enumeration data type. You must declare the enumeration data type before you can define a variable having that type. The first line of the following example declares the enumeration tag grain. The second line defines the variable g_food and gives g_food the initial value of barley (2). The type specifier enum grain indicates that the value of g_food is a member of the enumerated data type grain: In C++, the value of g_food has the enumerated data type grain. enum grain { oats, wheat, barley, corn, rice }; enum grain g_food = barley; The initializer for an enumeration variable contains the = symbol followed by an expression. In C, the expression must evaluate to an int value. In C++, the expression must be have the same type as the associated enumeration type. C++ also makes the enum keyword optional in an initialization expression like the one in the second line of the preceding example. For example, both of the following statements are valid C++ code: enum grain g_food = barley; grain cob_food = corn; ═══ 5.7.5.2. Defining Enumeration Types and Objects ═══ You can place a type definition and a variable definition in one statement by placing a declarator and an optional initializer after the type definition. If you want to specify a storage class specifier for the variable, you must place the storage class specifier at the beginning of the declaration. For example: register enum score { poor=1, average, good } rating = good; C++ also allows you to place the storage class immediately before the declarator. For example: enum score { poor=1, average, good } register rating = good; Either of these examples is equivalent to the following two declarations: enum score { poor=1, average, good }; register enum score rating = good; Both examples define the enumeration data type score and the variable rating. rating has the storage class specifier register, the data type enum score, and the initial value good. If you combine a data type definition with the definitions of all variables having that data type, you can leave the data type unnamed. For example: enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } weekday; This example defines the variable weekday, which can be assigned any of the specified enumeration constants. ═══ 5.7.5.3. Example Program Using Enumerations ═══ /********************************************************************************** * The following program receives an integer as input. The output is a sentence that gives the French name for the weekday that is associated with the integer. If the integer is not associated with a weekday, the program prints "C'est le mauvais jour." * ************************************************************************/ #include enum days { Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } weekday; void french(enum days); int main(void) { int num; printf("Enter an integer for the day of the week. " "Mon=1,...,Sun=7\n"); scanf("%d", &num); weekday=num; french(weekday); } void french(enum days weekday); { switch (weekday) { case Monday: printf("Le jour de la semaine est lundi.\n"); break; case Tuesday: printf("Le jour de la semaine est mardi.\n"); break; case Wednesday: printf("Le jour de la semaine est mercredi.\n"); break; case Thursday: printf("Le jour de la semaine est jeudi.\n"); break; case Friday: printf("Le jour de la semaine est vendredi.\n"); break; case Saturday: printf("Le jour de la semaine est samedi.\n"); break; case Sunday: printf("Le jour de la semaine est dimanche.\n"); break; default: printf("C'est le mauvais jour.\n"); } } ═══ 5.7.6. Arrays ═══ An array is an ordered group of data objects. Each object is called an element. All elements within an array have the same data type. You can use any type specifier in an array definition or declaration. Thus, array elements can be of any data type, except function or reference. (You can, however, declare an array of pointers to functions.) The declarator contains an identifier followed by a subscript declarator. The identifier can be preceded by an * (asterisk), making the variable an array of pointers. The subscript declarator describes the number of dimensions in the array and the number of elements in each dimension. Syntax of a Subscript Declarator Each bracketed expression, or subscript, describes a different dimension and must be a constant expression. The constant expression must have an integral value. The value of the constant expression determines the number of elements in that dimension. The following example defines a one-dimensional array that contains four elements having type char: char list[4]; The first subscript of each dimension is 0. Thus, the array list contains the elements: list[0] list[1] list[2] list[3] The following example defines a two-dimensional array that contains six elements of type int: int roster[3][2]; Multidimensional arrays are stored in row-major order; when elements are referenced in order of increasing storage location, the last subscript varies the fastest. For example, the elements of array roster are stored in the order: roster[0][0] roster[0][1] roster[1][0] roster[1][1] roster[2][0] roster[2][1] In storage, the elements of roster would be stored as: │ │ │ └ ────────── ───── ┴ ────────── ───── ┴ ────────── ─────    │ │ │ roster [ 0 ] [ 0 ] roster [ 0 ] [ 1 ] roster [ 1 ] [ 0 ] You can leave the first (and only the first) set of subscript brackets empty in o Array definitions that contain initializations o extern declarations o Parameter declarations. In array definitions that leave the first set of subscript brackets empty, the compiler uses the initializer to determine the number of elements in the first dimension. In a one-dimensional array, the number of initialized elements becomes the total number of elements. In a multidimensional array, the compiler compares the initializer to the subscript declarator to determine the number of elements in the first dimension. An unsubscripted array name (for example, region instead of region[4]) represents a pointer whose value is the address of the first element of the array. For more information, see Primary Expression. Whenever an array is used in a context (such as a parameter) where it cannot be used as an array, the identifier is treated as a pointer. The two exceptions are when an array is used as an operand of the sizeof or the address (&) operator. Additional information is provided on: o Initializing Arrays o Example Programs Using Arrays Related Information o Pointers o Array Subscript [ ] o Strings o Declarators o Initializers o Conversions ═══ Syntax of a Subscript Declarator ═══ A subscript declarator has the form: ──[──┬───────────────────────┬──]─┬───────────────────────────────┬─ │ │ │ ┌───────────────────────────┐ │ └──constant_expression──┘ │  │ │ └───[──constant_expression──]─┴─┘ ═══ 5.7.6.1. Initializing Arrays ═══ The initializer contains the = symbol followed by a brace-enclosed comma-separated list of constant expressions. You do not need to initialize all elements in an array. Elements that are not initialized (in extern and static definitions only) receive the value 0. You can initialize a one-dimensional character array by specifying: o A brace-enclosed comma-separated list of constants, each of which can be contained in a character o A string constant. (Braces surrounding the constant are optional.) If you specify a string constant, the null character (\0) is placed at the end of the string if there is room or if the array dimensions are not specified. Examples of Initialized Arrays Note that the following definition would result in the null character being lost: static char name[3]="Jan"; You can initialize a multidimensional array by: o Listing the values of all elements you want to initialize, in the order that the compiler assigns the values. The compiler assigns values by increasing the subscript of the last dimension fastest. This form of a multidimensional array initialization looks like a one-dimensional array initialization. The following definition completely initializes the array month_days: static month_days[2][12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; o Using braces to group the values of the elements you want initialized. You can place braces around each element, or around any nesting level of elements. The following definition contains two elements in the first dimension. (You can consider these elements as rows.) The initialization contains braces around each of these two elements: static int month_days[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; You can use nested braces to initialize dimensions and elements in a dimension selectively. Note: When using braces, you should place braces around each dimension (fully braced), or only use one set of braces to enclose the entire set of initializers (unbraced). Avoid putting braces around some elements and not others. You cannot have more initializers than the number of elements in the array. ═══ Examples of Initialized Arrays ═══ The following definition shows a completely initialized one-dimensional array: static int number[3] = { 5, 7, 2 }; The array number contains the following values: Element Value number[0] 5 number[1] 7 number[2] 2 The following definition shows a partially initialized one-dimensional array: static int number1[3] = { 5, 7 }; The values of number1 are: Element Value number1[0] 5 number1[1] 7 number1[2] 0 Instead of an expression in the subscript declarator defining the number of elements, the following one-dimensional array definition defines one element for each initializer specified: static int item[ ] = { 1, 2, 3, 4, 5 }; The compiler gives item the five initialized elements: Element Value item[0] 1 item[1] 2 item[2] 3 item[3] 4 item[4] 5 The following definitions show character array initializations: static char name1[ ] = { 'J', 'a', 'n' }; static char name2[ ] = { "Jan" }; static char name3[4] = "Jan"; These definitions create the following elements: Element Value name1[0] J name1[1] a name1[2] n name2[0] J name2[1] a name2[2] n name2[3] \0 name3[0] J name3[1] a name3[2] n The following definition explicitly initializes six elements in a 12-element array: static int matrix[3][4] = { {1, 2}, {3, 4}, {5, 6} }; The initial values of matrix are: ┌───────────────────┬───────────────────┬───────────────────┬──────────────────┐ │ ELEMENT │ VALUE │ ELEMENT │ VALUE │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[0][0]" │ "1" │ "matrix[1][2]" │ "0" │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[0][1]" │ "2" │ "matrix[1][3]" │ "0" │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[0][2]" │ "0" │ "matrix[2][0]" │ "5" │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[0][3]" │ "0" │ "matrix[2][1]" │ "6" │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[1][0]" │ "3" │ "matrix[2][2]" │ "0" │ ├───────────────────┼───────────────────┼───────────────────┼──────────────────┤ │ "matrix[1][1]" │ "4" │ "matrix[2][3]" │ "0" │ └───────────────────┴───────────────────┴───────────────────┴──────────────────┘ ═══ 5.7.6.2. Example Programs Using Arrays ═══ /************************************************************************ * The following program defines a floating-point array called prices. The first for statement prints the values of the elements of prices. The second for statement adds five percent to the value of each element of prices, and assigns the result to total, and prints the value of total. * ************************************************************************/ /* Example of one-dimensional arrays. */ #include #define ARR_SIZE 5 int main(void) { static float const prices[ARR_SIZE] = { 1.41, 1.50, 3.75, 5.00, .86 }; auto float total; int i; for (i = 0; i < ARR_SIZE; i++) { printf("price = $%.2f\n", prices[i]); } printf("\n"); for (i = 0; i < ARR_SIZE; i++) { total = prices[i] * 1.05; printf("total = $%.2f\n", total); } } /************************************************************************ * The preceding program produces the following output: price = $1.41 price = $1.50 price = $3.75 price = $5.00 price = $0.86 total = $1.48 total = $1.57 total = $3.94 total = $5.25 total = $0.90 The following program defines the multidimensional array salary_tbl. A for loop prints the values of salary_tbl. * ************************************************************************/ /* example of a multidimensional array */ #include #define NUM_ROW 3 #define NUM_COLUMN 5 int main(void) { static int salary_tbl[NUM_ROW][NUM_COLUMN] = { { 500, 550, 600, 650, 700 }, { 600, 670, 740, 810, 880 }, { 740, 840, 940, 1040, 1140 } }; int grade , step; for (grade = 0; grade < NUM_ROW; ++grade) for (step = 0; step < NUM_COLUMN; ++step) { printf("salary_tbl[%d] [%d] = %d\n", grade, step, salary_tbl[grade] [step]); } } /************************************************************************ * The preceding program produces the following output: salary_tbl[0] [0] = 500 salary_tbl[0] [1] = 550 salary_tbl[0] [2] = 600 salary_tbl[0] [3] = 650 salary_tbl[0] [4] = 700 salary_tbl[1] [0] = 600 salary_tbl[1] [1] = 670 salary_tbl[1] [2] = 740 salary_tbl[1] [3] = 810 salary_tbl[1] [4] = 880 salary_tbl[2] [0] = 740 salary_tbl[2] [1] = 840 salary_tbl[2] [2] = 940 salary_tbl[2] [3] = 1040 salary_tbl[2] [4] = 1140 * ************************************************************************/ ═══ 5.7.7. Pointers ═══ A pointer type variable holds the address of a data object or a function. A pointer can refer to an object of any one data type except to a bit field or a reference. Additionally, in C, a pointer cannot point to an object with the register storage class. Some common uses for pointers are: o To pass the address of a variable to a function. (You can also use a reference to do this.) By referencing a variable through its address, a function can change the contents of that variable. See Calling Functions and Passing Arguments. o To access dynamic data structures such as linked lists, trees, and queues. o To access elements of an array or members of a structure or class. o To access an array of characters as a string. The following example declares pcoat as a pointer to an object having type long: extern long *pcoat; If the keyword volatile appears before the *, the declarator describes a pointer to a volatile object. If the keyword volatile comes between the * and the identifier, the declarator describes a volatile pointer. The keyword const operates in the same manner as the volatile keyword. Examples of Pointer Declarations Additional information is provided on: o Initializing Pointers o Restrictions o Using Pointers o Pointer Arithmetic o Example Program Using Pointers Related Information o Address & o Indirection * o _Seg16 Type Qualifier o References o Declarators o volatile and const Qualifiers o Initializers ═══ Examples of Pointer Declarations ═══ In the following example, pvolt is a constant pointer to an object having type short: short * const pvolt; The following example declares pnut as a pointer to an int object having the volatile qualifier: extern int volatile *pnut; The following example defines psoup as a volatile pointer to an object having type float: float * volatile psoup; The following example defines pfowl as a pointer to an enumeration object of type bird: enum bird *pfowl; The next example declares x as a pointer to a function that returns a char object: char (*x)(void); ═══ 5.7.7.1. Initializing Pointers ═══ When you use pointers in an assignment operation, you must ensure that the types of the pointers in the operation are compatible. The following example shows compatible declarations for the assignment operation: float subtotal; float * sub_ptr; . . . sub_ptr = &subtotal; printf("The subtotal is %f\n", *sub_ptr); The next example shows incompatible declarations for the assignment operation: double league; int * minor; . . . minor = &league; /* error */ The initializer is an = (equal sign) followed by the expression that represents the address that the pointer is to contain. The following example defines the variables time and speed as having type double and amount as having type pointer to a double. The pointer amount is initialized to point to total: double total, speed, *amount = &total; The compiler converts an unsubscripted array name to a pointer to the first element in the array. You can assign the address of the first element of an array to a pointer by specifying the name of the array. The following two sets of definitions are equivalent. Both define the pointer student and initialize student to the address of the first element in class: int class[80]; int *student = class; is equivalent to: int class[80]; int *student = &class[0]; You can assign the address of the first character in a string constant to a pointer by specifying the string constant in the initializer. The following example defines the pointer variable string and the string constant "abcd". The pointer string is initialized to point to the character a in the string "abcd". char *string = "abcd"; The following example defines weekdays as an array of pointers to string constants. Each element points to a different string. The object weekdays[2], for example, points to the string "Tuesday". static char *weekdays[ ] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; A pointer can also be initialized to the integer constant 0. Such a pointer is a NULL pointer that does not point to any object. ═══ 5.7.7.2. Restrictions ═══ You cannot use pointers to reference bit fields or objects having the register storage class specifier. A pointer to a packed structure or union is incompatible with a pointer to a corresponding nonpacked structure or union because packed and nonpacked objects have different memory layouts. As a result, comparisons and assignments between pointers to packed and nonpacked objects are not valid. You can, however, perform these assignments and comparisons with type casts. Consider the following example: int main(void) { _Packed struct ss *ps1; struct ss *ps2; . . . ps1 = (_Packed struct ss *)ps2; . . . } In the preceding example, the cast operation allows you to compare the two pointers, but you must be aware that ps1 still points to a nonpacked object. For the C/C++ Tools compiler, all pointers that are shared between 32-bit and 16-bit code must be declared with the _Seg16 type qualifier. This includes pointers that are indirectly passed to 16-bit code, such as pointers in structures and pointers that are referenced by pointers directly passed to 16-bit code. For more information, see _Seg16 Type Qualifier and the chapter on "Calling Between 32-Bit adnd 16-Bit Code" in the Programming Guide. ═══ 5.7.7.3. Using Pointers ═══ Two operators are commonly used in working with pointers, the & (address) operator and the * (indirection) operator. You can use the & operator to reference the address of an object. For example, the following statement assigns the address of x to the variable p_to_x. The variable p_to_x has been defined as a pointer. int x, *p_to_x; p_to_x = &x; The * (indirection) operator enables you to access the value of the object to which a pointer refers. The following statement assigns to y the value of the object to which p_to_x points: float y, *p_to_x; . . . y = *p_to_x; The following statement assigns the value of y to the variable that *p_to_x references: char y , *p_to_x, . . . *p_to_x = y; ═══ 5.7.7.4. Pointer Arithmetic ═══ You can perform a limited number of arithmetic operations on pointers. These operations are: These operations are: o Increment and decrement o Addition and subtraction o Comparison o Assignment. The ++ (increment) operator increases the value of a pointer by the size of the data object to which the pointer refers. For example, if the pointer refers to the second element in an array, the ++ makes the pointer refer to the third element in the array. The -- (decrement) operator decreases the value of a pointer by the size of the data object to which the pointer refers. For example, if the pointer refers to the second element in an array, the -- makes the pointer refer to the first element in the array. If the pointer p points to the first element in an array, the following expression causes the pointer to point to the third element in the same array: p = p + 2; If you have two pointers that point to the same array, you can subtract one pointer from the other. This operation yields the number of elements in the array that separate the two addresses to which the pointers refer. You can compare two pointers with the following operators: ==, !=, <, >, <=, and >=. See Expressions and Operators for more information on these operators. Pointer comparisons are defined only when the pointers point to elements of the same array. You can assign to a pointer the address of a data object, the value of another compatible pointer or the NULL pointer. ═══ 5.7.7.5. Example Program Using Pointers ═══ /************************************************************************ * The following program contains pointer arrays: * ************************************************************************/ /******************************************************************** ** Program to search for the first occurrence of a specified ** ** character string in an array of character strings. ** ********************************************************************/ #include #define SIZE 20 int main(void) { static char *names[ ] = { "Jim", "Amy", "Mark", "Sue", NULL }; char * find_name(char **, char *); char new_name[SIZE], *name_pointer; printf("Enter name to be searched.\n"); scanf("%s", new_name); name_pointer = find_name(names, new_name); printf("name %s%sfound\n", new_name, (name_pointer == NULL) ? " not " : " "); exit(EXIT_FAILURE); } /* End of main */ /******************************************************************** ** Function find_name. This function searches an array of ** ** names to see if a given name already exists in the array. ** ** It returns a pointer to the name or NULL if the name is ** ** not found. ** ********************************************************************/ /* char **arry is a pointer to arrays of pointers (existing names) */ /* char *strng is a pointer to character array entered (new name) */ char * find_name(char **arry, char *strng) { for (; *arry != NULL; arry++) /* for each name */ { if (strcmp(*arry, strng) == 0) /* if strings match */ return(*arry); /* found it! */ } return(*arry); /* return the pointer */ } /* End of find_name */ /************************************************************************ * Interaction with the preceding program could produce the following sessions: Output Enter name to be searched. Input Mark Output name Mark found or: Output Enter name to be searched. Input Bob Output name Bob not found * ************************************************************************/ ═══ 5.7.8. References ═══ A reference is an alias or an alternative name for an object. All operations applied to a reference act on the object to which the reference refers. The address of a reference is the address of the aliased object. A reference type is defined by placing the & after the type specifier. You must initialize a reference when it is defined. Because arguments are passed by value, a function call does not modify the actual values of the arguments. If a function needs to modify the actual value of an argument, the argument must be passed by reference (as opposed to being passed by value). Passing arguments by reference can be done using either references or pointers. In C++, this is accomplished transparently. Unlike C, C++ does not force you to use pointers if you want to pass arguments by reference. For example: int f(int&); void main() { extern int i; f(i); } You cannot tell from the function call f(i) that the argument is being passed by reference. NULL references are not allowed. Additional information is provided on Initializing References. Related Information o Passing Arguments by Reference o Pointers o Declarators o Initializers ═══ 5.7.8.1. Initializing References ═══ The object that you use to initialize a reference must be of the same type as the reference, or it must be of a type that is convertible to the reference type. If you initialize a constant reference using an object that requires conversion, a temporary object is created. In the following example, a temporary object of type float is created: int i; const float& f = i; Attempting to initialize a nonconstant reference with an object that requires a conversion is an error. Once a reference has been initialized, it cannot be modified to refer to another object. For example: int num1 = 10; int num2 = 20; int &RefOne = num1; // valid int &RefOne = num2; // error, two definitions of RefOne RefOne = num2; // assign num2 to num1 int &RefTwo; // error, uninitialized reference int &RefTwo = num2; // valid Note that the initialization of a reference is not the same as an assignment to a reference. Initialization operates on the actual reference by initializing the reference with the object it is an alias for. Assignment operates through the reference on the object referred to. A reference can be declared without an initializer: o When it is used in an argument declaration o In the declaration of a return type for a function call o In the declaration of class member within its class declaration o When the extern specifier is explicitly used You cannot have references to references, references to bit fields, arrays of references, or pointers to references. ═══ 5.7.9. Structures ═══ A structure contains an ordered group of data objects. Unlike the elements of an array, the data objects within a structure can have varied data types. Each data object in a structure is a member or field. You can use structures to group logically related objects. For example, if you want to allocate storage for the components of one address, you can define a number of variables for the street name and number, the city, and so on. If you want to allocate storage for more than one address, however, you can group the components of each address by defining a structure data type and defining several variables having the structure data type: 1 struct address { 2 int street_no; 3 char *street_name; 4 char *city; 5 char *prov; 6 char *postal_code; 7 }; 8 struct address perm_address; 9 struct address temp_address; 10 struct address *p_perm_address = &perm_address; Lines 1 through 7 declare the structure tag address. Line 8 defines the variable perm_address, and line 9 defines the variable temp_address, both of which are instances of the structure address. Both perm_address and temp_address contain the members described in lines 2 through 6. Line 10 defines a pointer p_perm_address, which points to a structure of address. p_perm_address is initialized to point to perm_address. You can reference a member of a structure by specifying the structure variable name with the . (dot operator) or a pointer with the -> (arrow operator) and the member name. For example, both of the following: perm_address.prov = "Ontario"; p_perm_address -> prov = "Ontario"; assign a pointer to the string "Ontario" to the pointer prov that is in the structure perm_address. All references to structures must be fully qualified. Therefore, in the preceding example, you cannot reference the fourth field by prov alone. You must reference this field by perm_address.prov. You cannot declare a structure with members of incomplete types. A structure type declaration does not allocate storage. It describes the members that are part of the structure. A structure type declaration contains the struct keyword followed by an optional identifier (the structure tag) and a brace-enclosed list of members. Syntax of a Structure The keyword struct followed by the identifier (tag) names the data type. If you do not provide a tag, you must place all variable definitions that refer to that data type within the statement that defines the data type. The list of members provides the data type with a description of the values that can be stored in the structure. A member that does not represent a bit field can be of any data type and can have the volatile or const qualifier. If a : (colon) and a constant expression follow the declarator, the member represents a bit field. Identifiers used as aggregate or member names can be redefined to represent different objects in the same scope without conflicting. You cannot use the name of a member more than once in a structure type, but you can use the same member name in another structure type that is defined within the same scope. You cannot declare a structure type that contains itself as a member but you can declare a structure type that contains a pointer to itself as a member. A structure variable definition contains an optional storage class keyword, the struct keyword, a structure tag, a declarator, and an optional identifier. The structure tag indicates the data type of the structure variable. You can declare structures having any storage class. Additional information is provided on: o Declaring Structure Types and Variables o Initializing Structures o Declaring and Using Bit Fields in Structures o Declaring a Packed Structure o Example Program Using Structures Related Information o Dot Operator o Arrow Operator o _Packed Qualifier o Declarators o Initializers ═══ Syntax of a Structure ═══ A structure declaration has the form: ┬───────────┬──struct──┬─────────identifier─────────────────┬── │ │ │ ┌───────────┐ │ └──_Packed──┘ │  │ │ ├──────────────┬──{───member─;──┴─}──┘ │ │ └──identifier──┘ A structure member has the form: ┌─────────────────,────────────────────────┐  │ ──type_specifier──┬────────────declarator──────────────────┬┴─ │ │ ├──────────────┬──:──constant_expression─┘ │ │ └──declarator──┘ ═══ 5.7.9.1. Initializing Structures ═══ The initializer contains an = (equal sign) followed by a brace-enclosed comma-separated list of values. You do not have to initialize all members of a structure. The following definition shows a completely initialized structure: struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; static struct address perm_address = { 9876, "Goto St.", "Cville", "Ontario", "X9X 1A1"}; The values of perm_address are: Member Value perm_address.street_no 9876 perm_address.street_name address of string "Goto St." perm_address.city address of string "Cville" perm_address.prov address of string "Ontario" perm_address.postal_code address of string "X9X 1A1" The following definition shows a partially initialized structure: struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; struct address temp_address = { 321, "Aggregate Ave.", "Structown", "Ontario" }; The values of temp_address are: Member Value temp_address.street_no 321 temp_address.street_name address of string "Aggregate Ave." temp_address.city address of string "Structown" temp_address.prov address of string "Ontario" temp_address.postal_code value depends on the storage class. Note: The initial value of uninitialized structure members like temp_address.postal_code depends on the storage class associated with the member. See Storage Class Specifiers for details on the initialization of different storage classes. ═══ 5.7.9.2. Declaring Structure Types and Variables ═══ You can place a type definition and a variable declaration in one statement by placing a declarator and an initializer (optional) after the type definition. If you want to specify a storage class specifier for the variable, you must place the storage class specifier at the beginning of the statement. For example: static struct { int street_no; char *street_name; char *city; char *prov; char *postal_code; } perm_address, temp_address; The preceding example does not name the structure data type. Thus, perm_address and temp_address are the only structure variables that will have this data type. If an identifier is placed after struct, additional variable definitions of this data type can be made later in the program. The structure type (or tag) cannot have the volatile qualifier, but a member or a structure variable can be defined as having the volatile qualifier. For example: static struct class1 { char descript[20]; volatile long code; short complete; } volatile file1, file2; struct class1 subfile; This example gives the volatile qualifier to the structures file1 and file2, and to the structure member subfile.code. ═══ 5.7.9.3. Declaring and Using Bit Fields ═══ A structure can contain bit fields that allow you to access individual bits. You can use bit fields for data that requires just a few bits of storage. A bit field declaration contains a type specifier followed by an optional declarator, a colon, a constant expression, and a semicolon. The constant expression specifies how many bits the field reserves. A bit field that is declared as having a length of 0 causes the next field to be aligned on the next integer boundary. For a _Packed structure, a bit field of length 0 causes the next field to be aligned on the next byte boundary. Bit fields with a length of 0 must be unnamed. For portability, do not use bit fields greater than 32 bits in size. You cannot define an array of bit fields, or take the address of a bit field. You can declare a bit field as type int, signed int, or unsigned int. Bit fields of the type int are equivalent to those of type unsigned int. If a series of bit fields does not add up to the size of an int, padding can take place. The amount of padding is determined by the alignment characteristics of the members of the structure. In some instances, bit fields can cross word boundaries. The following example declares the identifier kitchen to be of type struct on_off: struct on_off { unsigned light : 1; unsigned toaster : 1; int count; unsigned ac : 4; unsigned : 4; unsigned clock : 1; unsigned : 0; unsigned flag : 1; } kitchen ; The structure kitchen contains eight members. The following table describes the storage that each member occupies: Member Name Storage Occupied light 1 bit toaster 1 bit, and padding to next int boundary (unnamed field) count The size of an int ac 4 bits 4 bits (unnamed field) clock 1 bit padding to next int boundary (unnamed field) flag 1 bit All references to structure fields must be fully qualified. Therefore, you cannot reference the second field by toaster. You must reference this field by kitchen.toaster. The following expression sets the light field to 1: kitchen.light = 1; When you assign to a bit field a value that is out of its range, the bit pattern is preserved and the appropriate bits are assigned. The following expression sets the toaster field of the kitchen structure to 0 because only the least significant bit is assigned to the toaster field: kitchen.toaster = 2; ═══ 5.7.9.4. Declaring a Packed Structure ═══ Data elements of a structure are stored in memory on an address boundary specific for that data type. For example, a double value is stored in memory on a doubleword (8-byte) boundary. Gaps may be left in memory between elements of a structure to align elements on their natural boundaries. You can reduce the padding of bytes within a structure by using the _Packed qualifier on the structure declaration. C++ Consideration: C++ does not support the _Packed qualifier. To change the alignment of structures, use the #pragma pack directive or the /Sp compiler option. Both of these methods are also supported by C. ═══ 5.7.9.5. Example Program Using Structures ═══ /************************************************************************ * The following program finds the sum of the integer numbers in a linked list: * ************************************************************************/ /* program to illustrate linked lists */ #include struct record { int number; struct record *next_num; }; int main(void) { struct record name1, name2, name3; struct record *recd_pointer = &name1; int sum = 0; name1.number = 144; name2.number = 203; name3.number = 488; name1.next_num = &name2; name2.next_num = &name3; name3.next_num = NULL; while (recd_pointer != NULL) { sum += recd_pointer->number; recd_pointer = recd_pointer->next_num; } printf("Sum = %d\n", sum); } /************************************************************************ * The structure type record contains two members: number (an integer) and next_num (a pointer to a structure variable of type record). The record type variables name1, name2, and name3 are assigned the following values: Member Name Value name1.number 144 name1.next_num The address of name2 name2.number 203 name2.next_num The address of name3 name3.number 488 name3.next_num NULL (Indicating the end of the linked list.) The variable recd_pointer is a pointer to a structure of type record. recd_pointer is initialized to the address of name1 (the beginning of the linked list). The while loop causes the linked list to be scanned until recd_pointer equals NULL. The statement: recd_pointer = recd_pointer->next_num; advances the pointer to the next object in the list. * ***********************************************************************************/ ═══ 5.7.10. Unions ═══ A union is an object that can hold any one of a set of named members. The members of the named set can be of any data type. Members are overlaid in storage. The storage allocated for a union is the storage required for the largest member of the union (plus any padding that is required so that the union will end at a natural boundary of its strictest member). A union type declaration contains the union keyword followed by an identifier (optional) and a brace-enclosed list of members. Syntax of a Union The identifier is a tag given to the union specified by the member list. If you specify a tag, any subsequent declaration of the union (in the same scope) can be made by declaring the tag and omitting the member list. If you do not specify a tag, you must place all variable definitions that refer to that union within the statement that defines the data type. The list of members provides the data type with a description of the objects that can be stored in the union. A union can have member functions, including constructors and destructors, but not virtual member functions. A union cannot be used as a base class and cannot be derived from a base class. A union member cannot be a class object that has a constructor, destructor, or overloaded copy assignment operator. In C++, a member of a union cannot be declared with the keyword static. You can reference one of the possible members of a union as you reference a member of a structure. For example: union { char birthday[9]; int sex:1; /* 0 = male; 1 = female */ float weight; } people; people.birthday[0] = '\n'; assigns '\n' to the first element in the character array birthday, a member of the union people. At any given time, a union can represent only one of its members. In the preceding example, the union people will contain either sex, birthday, or weight but never more than one of these. For example, the following is not allowed: 1 people.birthday = "25/10/67"; 2 people.sex = 1; 3 printf("%d\n", people.weight); Both lines 2 and 3 are not allowed because in line 1, people.birthday is assigned a value. Examples of Unions Additional information is provided on: o Defining a Union Variable o Defining a Packed Union o Anonymous Unions in C o Anonymous Unions in C++ Related Information o Dot Operator o Arrow Operator o _Packed Qualifier o Declarators o Initializers ═══ Syntax of a Union ═══ The following diagram shows the form of a union type declaration: ┌─────────────┐  │ >>──┬───────────┬──union──┬────────────┬──{────member──???─┴──}──>< └─qualifier─┘ └─identifier─┘ A member has the form: ┌─,──────────────────────────────────────────┐  │ >>──type_specifier───┬─declarator───────────────────────────────┬┴──>< └─┬────────────┬──???──constant_expression─┘ └─declarator─┘ ═══ 5.7.10.1. Defining a Union Variable ═══ A union variable definition contains an optional storage class keyword, the union keyword, a union tag, and a declarator. The union tag indicates the data type of the union variable. The type specifier contains the keyword union followed by the name of the union type. You must declare the union data type before you can define a union having that type. You can define a union data type and a union of that type in the same statement by placing the variable declarator after the data type definition. The declarator is an identifier, possibly with the volatile or const qualifier. You can only initialize the first member of a union. The following example shows how you would initialize the first union member birthday of the union variable people: union { char birthday[9]; int age; float weight; } people = {"04/06/57"}; You can place a type definition and a variable definition in one statement by placing a declarator after the type definition. If you want to specify a storage class specifier for the variable, you must place the storage class specifier at the beginning of the statement. ═══ 5.7.10.2. Defining a Packed Union ═══ You can use _Packed to qualify a union. However, the memory layout of the union members is not affected. Each member starts at offset zero. The _Packed qualifier does affect the total alignment restriction of the whole union. C++ Consideration: C++ does not support the _Packed qualifier. To change the alignment of unions, use the #pragma pack directive or the /Sp compiler option. Both of these methods are also supported by C. Consider the following example: union uu { short a; struct { char x; char y; char z; } b; }; union uu n_array[2]; _Packed union uu p_array[2]; Each of the elements in the nonpacked n_array is of type union uu. Because it is nonpacked, each element has an alignment restriction of 2 bytes (the largest alignment requirement among the union members is that of short a), and there is 1 byte of padding at the end of each element to enforce this requirement. Now consider the packed array p_array. Because each of its elements is of type _Packed union uu, the alignment restriction of every element is the byte boundary. Therefore, each element has a length of only 3 bytes, instead of the 4 bytes in the previous example. ═══ 5.7.10.3. Anonymous Unions in C ═══ The C/C++ Tools compiler allows unions to be declared without declarators if they are members of another structure or union. Unions without declarators are called anonymous unions. Members of an anonymous union can be accessed as if they were declared directly in the containing structure or union. For example, given the following structure: struct s { int a; union { int b; float c; }; /* no declarator */ } kurt; you can make the following statements: kurt.a = 5; kurt.b = 36; You can also declare an anonymous union: 1. By creating a typedef and using the typedef name without a declarator: typedef union { int a; int b; } UNION_T; struct s1 { UNION_T; int c; } dave; 2. By using an existing union tag without a declarator: union u1 { int a; int b; }; struct s1 { union u1; int c; } dave; In both of the preceding examples, the members can be accessed as dave.a, dave.b, and dave.c. An anonymous union must be a member of, or nested within another anonymous union that is a member of, a named structure or union. If a union is declared at file scope without a declarator, its members are not available to the surrounding scope. For example, the following union only declares the union tag tom: union tom { int b; float c; }; The variables b and c from this union cannot be used at file scope, and the following statements will generate errors: b = 5; c = 2.5; C++ Consideration: Anonymous unions are treated differently in C++. See Anonymous Unions in C++ for more information. ═══ 5.7.10.4. Anonymous Unions in C++ ═══ An anonymous union is a union without a class name. It cannot be followed by a declarator. An anonymous union is not a type; it defines an unnamed object and it cannot have member functions. The member names of an anonymous union must be distinct from other names within the scope in which the union is declared. You can use member names directly in the union scope without any additional member access syntax. For example, in the following code fragment, you can access the data members i and cptr directly because they are in the scope containing the anonymous union. Because i and cptr are union members and have the same address, you should only use one of them at a time. The assignment to the member cptr will change the value of the member i. void f() { union { int i; char* cptr ; }; // . // . // . i = 5; cptr = "string_in_union"; // overrides i } An anonymous union cannot have protected or private members. A global anonymous union must be declared with the keyword static. ═══ Examples of Unions ═══ The following example defines a union data type (not named) and a union variable (named length). The member of length can be a long int, a float, or a double. union { float meters; double centimeters; long inches; } length; The following example defines the union type data as containing one member. The member can be named charctr, whole, or real. The second statement defines two data type variables: input and output. union data { char charctr; int whole; float real; }; union data input, output; The following statement assigns a character to input: input.charctr = 'h'; The following statement assigns a floating-point number to member output: output.real = 9.2; The following example defines an array of structures named records. Each element of records contains three members: the integer id_num, the integer type_of_input, and the union variable input. input has the union data type defined in the previous example. struct { int id_num; int type_of_input; union data input; } records[10]; The following statement assigns a character to the structure member input of the first element of records: records[0].input.charctr = 'g'; ═══ 5.7.11. typedef ═══ typedef declarations allow you to define your own identifiers that can be used in place of type specifiers such as int, float, and double. The data types you define using typedef are not new data types. The identifiers you define are synonyms for the primary data types used by the C language or data types derived by combining the primary data types. Syntax of a typedef Declaration A typedef declaration does not reserve storage. When an object is defined using a typedef identifier, the properties of the defined object are exactly the same as if the object were defined by explicitly listing the data type associated with the identifier. The following statements declare LENGTH as a synonym for int and then use this typedef to declare length, width, and height as integral variables: typedef int LENGTH; LENGTH length, width, height; The preceding lines are equivalent to the following: int length, width, height; Similarly, typedef can be used to define a class type (class, structure, or union). For example: typedef struct { int kilos; int grams; } WEIGHT; The structure WEIGHT can then be used in the following declarations: WEIGHT chicken, cow, horse, whale; A class defined in a typedef without being names is given a dummy name and the typedef name for linkage. Such a class cannot have constructors or destructors. For example: typedef class { Trees(); } Trees; Here the function Trees() is an ordinary member function of a class whose type name is unspecified. In the above example, Trees is an alias for the unnamed class, not the class type name itself, so Trees() cannot be a constructor for that class. Related Information o Characters o Floating-Point Variables o Integers o void Type o Arrays o Enumerations o Pointers o Structures o Unions o C++ Classes o Constructors and Destructors Overview ═══ Syntax of a typedef Declaration ═══ The syntax of a typedef declaration is: >>──typedef──type_specifier──identifier──???──>< ═══ 6. Functions ═══ Functions specify the logical structure of a program and define how particular operations are to be implemented. A function declaration consists of a return type, a name, and an argument list. It is used to declare the format and existence of a function prior to its use. Both C++ and ANSI C use the style of declaration called prototyping. C++ functions in particular must have a prototype. A prototype refers to the return type, name, and argument list components of a function. It is used by the compiler for argument type checking and argument conversions. Prototypes can appear several times in a program, provided the declarations are compatible. A function definition contains a function declaration and the body of the function. A function can only have one definition. Function prototypes are usually placed in header files, while function definitions appear in source files. This section describes the structure and usage of functions. o C++ Enhancements to C Functions o main o Function Definition o Function Declarations o Calling Functions and Passing Arguments o Default Arguments o Inline Functions ═══ 6.1. C++ Enhancements to C Functions ═══ The C++ language provides many enhancements to C functions. These are: o Reference arguments o Default arguments o Reference return types o Member functions o Overloaded functions o Operator functions o Constructor and destructor functions o Conversion functions o Virtual functions o Function templates ═══ 6.2. main ═══ When you begin the execution of a program, the system automatically calls the function main. Every program must have one function named main, with the name main written in lowercase letters. Syntax of the main Function By default, main has the storage class extern and a return type of int. It can also be declared to return void. You cannot use the inline or static specifiers when declaring main. You cannot call main from within a program or take the address of main. The function main can declare either none or two parameters. The C/C++ Tools compiler also supports an optional third parameter. Although any name can be given to these parameters, they are usually referred to as argc and argv. The third parameter is referred to as envp. The first parameter, argc (argument count), has type int and indicates how many arguments were entered on the command line. The second parameter, argv (argument vector), has type array of pointers to char array objects. char array objects are null-terminated strings. The third parameter, envp, is a pointer to an array of char pointers to the environment strings. A NULL pointer terminates the array. You can use the pointer to the array to access the value of the environment settings. The envp parameter is optional, but to declare it, you must also declare the first two parameters. Note: The envp parameter is not available when you are using the subsystem libraries. The value of argc indicates the number of pointers in the array argv. If a program name is available, the first element in argv points to a character array that contains the program name or the invocation name of the program that is being executed. If the name cannot be determined, the first element in argv points to a null character. This name is counted as one of the arguments to the function main. For example, if only the program name is entered on the command line, argc has a value of 1 and argv[0] points to the program name. Regardless of the number of arguments entered on the command line, argv[argc] always contains NULL. Example of Arguments to main Related Information o Function Definition o Calling Functions and Passing Arguments o Types o Identifiers o Block ═══ Syntax of the main Function ═══ The main function has the form: >>──┬─────┬──main──(──┬──────────────────────────────────────────────────┬──> └─int─┘ ├─void─────────────────────────────────────────────┤ └─int──argc──,──char *──argv[]──┬────────────────┬─┘ └─char *──envp[]─┘ >──)──block_statement──>< ═══ Example of Arguments to main ═══ /************************************************************************ * The following program backward prints the arguments entered on a command line such that the last argument is printed first: * ************************************************************************/ #include int main(int argc, char *argv[]) { while (--argc > 0) printf("%s ", argv[argc]); } /************************************************************************ * If you invoke this program from a command line with the following: backward string1 string2 The output generated is: string2 string1 The arguments argc and argv would contain the following values: Object Value argc 3 argv[0] pointer to string "backward" argv[1] pointer to string "string1" argv[2] pointer to string "string2" argv[3] NULL * ************************************************************************/ ═══ 6.3. Function Declarations ═══ A function declaration establishes the name and the parameters of the function. Syntax of a Function Declaration A function is declared implicitly by its appearance in an expression if it has not been defined or declared previously; the implicit declaration is equivalent to a declaration of extern int func_name(). If the called function returns a value that has a type other than int, you must declare the function before the function call. Even if a called function returns a type int, explicitly declaring the function prior to its call is good programming practice. In C++, you can specify the qualifiers volatile and const in member function declarations. You can also specify exception specifications in function declarations. Functions must be declared before they can be called. Types cannot be defined in return or argument types. For example, the following declarations are not valid in C++: void print(struct X { int i; } x); //error enum count{one, two, three} counter(); //error This example attempts to declare a function print() that takes an object x of class X as its argument. However, the class definition is not allowed within the argument list. In the attempt to declare counter(), the enumeration type definition cannot appear in the return type of the function declaration. The two function declarations and their corresponding type definitions can be rewritten as follows: struct X { int i; }; void print(X x); enum count {one, two, three}; count counter(); An ellipsis at the end of an argument declaration indicates that the number of arguments is equal to, or greater than, the number of specified argument types. Where it is permitted, an ellipsis preceded by a comma is equivalent to a simple ellipsis. An empty argument declaration list or the argument declaration list of (void) indicates a function that takes no arguments. void cannot be used as an argument type, although types derived from void (such as pointers to void) can be used. All function declarations for a particular function must have the same number and type of arguments, and must have the same return type and the same linkage keywords. These return and argument types are part of the function type, although the default arguments are not. For the purposes of argument matching, ellipsis and linkage keywords are considered a part of the function type. They must be used consistently in all declarations of a function. If the only difference between the argument types in two declarations is in the use of typedef names or unspecified argument array bounds, the declarations are the same. A const or volatile specifier is also part of the function type, but can only be part of a declaration or definition of a nonstatic member function. Declaring two functions differing only in return type is not valid function overloading, and is flagged as an error. For example: void f(); int f(); // error, two definitions differ only in // return type int g() { return f(); } Some declarations do not have parameter lists; the declarations simply specify the types of parameters and the return values, such as in the following example: int func(int,long); You can supply argument names in a function declaration, but the compiler ignores them except in the following two situations: 1. If two argument names have the same name within a single declaration. This is an error. 2. If an argument name is the same as a name outside the function. In this case the name outside the function is hidden and cannot be used in the argument declaration. In the following example, the third argument intersects is meant to have enumeration type subway_line, but this name is hidden by the name of the first argument. The declaration of the function subway() causes a compile-time error because subway_line is not a valid type name in the context of the argument declarations. enum subway_line {yonge, university, spadina, bloor}; int subway(char * subway_line, int stations, subway_line intersects); Examples of Function Declarations Examples of Function Declarations and Definitions Related Information o Function Declarator o Function Definition o Calling Functions and Passing Arguments o extern Storage Class Specifier ═══ Syntax of a Function Declaration ═══ A function declaration has the form: ┌─────────────┐  │ >>──┬────────┬──┬────────────────┬──function_declarator──(───┬───────────┬┴──> ├─extern─┤ └─type_specifier─┘ └─parameter─┘ └─static─┘ >──)──┬──────────┬──>< ├─const────┤ └─volatile─┘ The use of the const and volatile specifiers is only supported by C++. ═══ Examples of Function Declarations and Definitions ═══ /************************************************************************ * The following example defines the function absolute with the return type double. Because this is a noninteger return type, absolute is declared prior to the function call. * ************************************************************************/ #include double absolute(double); int main(void) { double f = -3.0; printf("absolute number = %lf\n", absolute(f)); } double absolute(double number) { if (number < 0.0) number = -number; return (number); } /************************************************************************ * Specifying a return type of void on a function declaration indicates that the function does not return a value. The following example defines the function absolute with the return type void. Within the function main, absolute is declared with the return type void. * ************************************************************************/ #include int main(void) { void absolute(float); float f = -8.7; absolute(f); } void absolute(float number) { if (number < 0.0) number = -number; printf("absolute number = %f\n", number); } ═══ Examples of Function Declarations ═══ You can declare a function with no arguments in two ways: int f(void); // ANSI C Standard int f(); // C++ enhancement // Note: In ANSI C, this declaration means that // f may take any number or type or parameters A function can also be declared with a variable number of arguments. To declare this type of function, use an ellipsis in the argument list in the function declaration as shown in the following example: int f(int,...); Note: The comma before the ellipsis in the above declaration is optional. No type checking is performed on the variable arguments. The following code fragments show several function declarations. The first declares a function f that takes two integer arguments and has a return type of void: void f(int, int); The following code fragment declares a function f1 that takes an integer argument, and returns a pointer to a function that takes an integer argument and returns an integer: int (*f1(int))(int); Alternatively, a typedef can be used for the complicated return type of function f1: typedef int pf1(int); pf1* f1(int); The following code fragment declares a pointer p1 to a function that takes a pointer to a constant character and returns an integer: int (*p1) (const char*); The following declaration is of an external function f2 that takes a constant integer as its first argument, can have a variable number and variable types of other arguments, and returns type int. int extern f2(const int ...); Function f3 takes an int argument with a default value that is the value returned from function f2, and that has a return type of int: const int j = 5; int f3( int x = f2(j) ); Function f6 is a constant class member function of class X with no arguments, and with an int return type: class X { public: int f6() const; }; Function f4 takes no arguments, has return type void, and can throw class objects of types X and Y. class X; class Y; // . // . // . void f4() throw(X,Y); Function f5 takes no arguments, has return type void, and cannot throw an exception. void f5() throw(); ═══ 6.4. Function Definition ═══ A function definition specifies the name, formal parameters, and body of a function. You can also specify the function's return type and storage class. Syntax of a Function Definition There are two ways to define a function: prototype and nonprototype. You should use the prototype method because of the parameter type checking that can be performed. Note: C++ functions must use prototypes. Nonprototype functions are allowed in C only. A function definition (either prototype or nonprototype) contains the following: o The optional storage class specifier extern or static, which determines the scope of the function. If a storage class specifier is not given, the function has external linkage. o An optional linkage keyword, which determines the calling convention used to call the function. The keywords are a C/C++ Tools extension to the SAA C definition. The default calling convention is _Optlink. o An optional type specifier, which determines the type of value that the function returns. If a type specifier is not given, the function has type int. o A function declarator, which provides the function with a name, can further describe the type of the value that the function returns, and can list any parameters (and their types) that the function expects. The parameters that the function is expecting are enclosed in parentheses. o A block statement, which contains data definitions and code. In addition, the nonprototype function definition may also have parameter declarations, which describe the types of parameters that the function receives. In nonprototype functions, parameters that are not declared have type int. A function can be called by itself or by other functions. Unless a function definition has the storage class specifier static, the function also can be called by functions that appear in other files. If the function has a storage class specifier of static, it can only be directly invoked from within the same source file. If a function has the storage class specifier static or a return type other than int, the function definition or a declaration for the function must appear before, and in the same file as, a call to the function. If a function definition has external linkage and a return type of int, calls to the function can be made before it is visible because an implicit declaration of extern int func(); is assumed. All declarations for a given function must be compatible; that is, the return type is the same and the parameters have the same type. The default type for the return value and parameters of a function is int, and the default storage class specifier is extern. If the function does not return a value or it is not passed any parameters, use the keyword void as the type specifier. You can include ellipses (...) at the end of your parameter list to indicate that a variable number of arguments will be passed to the function. Parameter promotions are performed, and no type checking is done. In C, you cannot declare a function as a struct or union member. (This restriction does not apply to C++.) A function cannot have a return type of function or array. In C, a function cannot return any type having the volatile or const qualifier. (This restriction does not apply to C++.) A function can return a pointer or reference to a function, array, or to an object with a volatile or const type. You cannot define an array of functions. You can, however, define an array of pointers to functions. Examples of Function Definitions Related Information o Storage Class Specifiers o Linkage Keywords o Types o Function Declarator o Block o volatile and const Qualifiers o Function Declarations ═══ Syntax of a Function Definition ═══ A function definition has the form: >>──┬────────┬──┬───────────────────┬──┬────────────────┬──> ├─extern─┤ └─linkage_specifier─┘ └─type_specifier─┘ └─static─┘ ┌─────────────────────────┐  │ >──function_declarator───┬───────────────────────┬┴──block_statement──>< └─parameter_declaration─┘ ═══ Examples of Function Definitions ═══ /************************************************************************ * In the following, ary is an array of two function pointers. Type casting is performed to the values assigned to ary for compatibility: * ************************************************************************/ #include int func1(void); void func2(double a); int main(void) { double num; void (*ary[2]) (); ary[0] = ((void(*)())func1); ary[1] = ((void(*)())func2); ((int (*)())ary[0])(); /* calls func1 */ ((void (*)(double))ary[1])(num); /* calls func2 */ } /************************************************************************ * The following example is a complete definition of the function sum: int sum(int x,int y) { return(x + y); } The function sum has external linkage, returns an object that has type int, and has two parameters of type int declared as x and y. The function body contains a single statement that returns the sum of x and y. * ************************************************************************/ ═══ 6.4.1. Linkage Keywords ═══ Linkage keywords are an alternative to the #pragma linkage directive for setting linkage conventions for function calls. Because C++ does not support #pragma linkage, linkage keywords are the only method for setting the calling conventions for C++ functions. Each linkage convention has a corresponding keyword that you can use with a function name to set the convention for that function. The keywords are: _Optlink C/C++ Tools default linkage _System OS/2 system linkage _Pascal 32-bit _Pascal linkage _Far32 _Pascal 32-bit far _Pascal linkage _Far16 _Cdecl 16-bit _Cdecl linkage _Far16 _Pascal 16-bit _Pascal linkage _Far16 _Fastcall 16-bit _Fastcall linkage Note: 1. You must specify the _Far16 keyword to use a 16-bit calling convention. If you specify only _Far16, the _Far16 _Cdecl linkage is used. 2. Do not confuse the 32-bit _Pascal linkage with the 16-bit _Far16 _Pascal linkage. If you specify only the _Pascal keyword, the 32-bit convention is used. 3. _Far32 _Pascal linkage is only available when the /Gr+ option is specified. You can use the linkage keywords at any language level. Using a keyword is generally quicker and easier than using a #pragma linkage directive. To set the calling convention for a function, place the linkage keyword immediately before the function name. For example, int _System deborah(int); char (* _Far16 _Cdecl donna)(int); These two statements are equivalent to using the following #pragma linkage directives and declarations in C: #pragma linkage(deborah, system) int deborah(int); #pragma linkage(donnatype, far16 cdecl) typedef char donnatype(int); donnatype donna; Like the #pragma linkage directive, the linkage keywords take precedence over the compiler options that set calling conventions (/Mp and /Ms). If you specify conflicting linkage types for a function using both a #pragma linkage directive and a keyword, an error message is generated and your program will not compile. For more information on the different calling conventions and how they work, see the Programming Guide. Related Information o #pragma linkage o /Mp and /Ms options o Function Declarations o Function Definition ═══ 6.4.2. Function Declarator ═══ The function declarator names the function and lists the function parameters. A function declarator contains an identifier that names the function and a list of the function parameters. There are two types of function declarators: prototype and nonprototype. It is recommended you always use prototype function declarators because of the parameter checking that can be performed. C++ functions must have prototype function declarators. Syntax of a Function Declarator For prototype function declarators, each parameter should be declared within the function declarator. Any calls to the function must pass the same number of arguments as there are parameters in the declaration. To indicate that a function does not receive any values, use the keyword void in place of the parameter. For example: int stop(void) { } Examples of Prototype Function Declarators For nonprototype function declarators, each parameter should be declared in a parameter declaration list following the declarator. If a parameter is not declared, it has type int. char and short parameters are widened to int, and float to double. No type checking between the argument type and the parameter type is done for nonprototyped functions. As well, there are no checks to ensure that the number of arguments matches the number of parameters. Each value that a function receives should be declared in a parameter declaration list for nonprototype function definitions that follows the declarator. A parameter declaration determines the storage class specifier and the data type of the value. The only storage class specifier allowed is the register storage class specifier. Any type specifier for a parameter is allowed. If you do not specify the register storage class specifier, the parameter will have the auto storage class specifier. If you omit the type specifier and you are not using the prototype form to define the function, the parameter will have type int. int func(i,j) { /* i and j have type int */ } You cannot declare a parameter in the parameter declaration list if it is not listed within the declarator. Related Information o Function Declarations o Function Definition o Function Body o Functions o Declarations and Definitions ═══ Syntax of a Function Declarator ═══ A prototype function declarator has the form: ┌──────────────,────────────────┐  │ ──identifier──(───┬─────────────────────────────┬┴┬─────┬──)─── │ │ │ │ └─type_specifier──┬───────────┤ └─...─┘ │ │ └─parameter─┘ A nonprototype function declarator has the form: ┌─,───────────┐  │ >>──identifier──(───┬───────────┬┴──)──>< └─parameter─┘ A parameter list has the form: ┌─────,──────┐  │ ──┬───────────────────────────────┬───declarator─┴─;── │ │ ├────────────┬──type_specifier──┘ │ │ └──register──┘ ═══ Examples of Prototype Function Declarators ═══ The example below contains a function declarator sort with table declared as a pointer to int and length declared as type int. Note that arrays as parameters are implicitly converted to a pointer to the type. void sort(int table[ ], int length) { int i, j, temp; for (i = 0; i < length -1; i++) for (j = i + 1; j < length; j++) if (table[i] > table[j]) { temp = table[i]; table[i] = table[j]; table[j] = temp; } } The following examples contain prototype function declarators: double square(float x); int area(int x,int y); static char *search(char); The example below illustrates how a typedef identifier can be used in a function declarator: typedef struct tm_fmt { int minutes; int hours; char am_pm; } struct_t; long time_seconds(struct_t arrival) The following function set_date declares a pointer to a structure of type date as a parameter. date_ptr has the storage class specifier register. set_date(register struct date *date_ptr) { date_ptr->mon = 12; date_ptr->day = 25; date_ptr->year = 87; } ═══ 6.4.3. Function Body ═══ The body of a function is a block statement. (For more information on block statements, see Block.) The following function has an empty body: void stub1(void) { } The following function body contains a definition for the integer variable big_num, an if-else control statement, and a call to the function printf: void largest(int num1, int num2) { int big_num; if (num1 >= num2) big_num = num1; else big_num = num2; printf("big_num = %d\n", big_num); } Related Information o Block o Function Definition o Function Declarations ═══ 6.5. Calling Functions and Passing Arguments ═══ A function call specifies a function name and a list of arguments. The calling function passes the value of each argument to the specified function. The argument list is surrounded by parentheses, and each argument is separated by a comma. The argument list can be empty. The arguments to a function are evaluated before the function is called. When an argument is passed in a function call, the function receives a copy of the argument value. If the value of the argument is an address, the called function can use indirection to change the contents pointed to by the address. If a function or array is passed as an argument, the argument is converted to a pointer that points to the function or array. If a nonstatic member function is passed as an argument, the argument is converted to a pointer to member. Arguments passed to parameters in prototype declarations will be converted to the declared parameter type. For nonprototype function declarations, char and short parameters are promoted to int, and float to double. You can pass a packed structure argument to a function expecting a nonpacked structure of the same type and vice versa. (The same applies to packed and nonpacked unions.) Note: If you do not use a function prototype and you send a packed structure when a nonpacked structure is expected, a runtime error may occur. It is an error when a function argument is a class and all of the following properties hold: o The class needs a copy constructor. o The class does not have a user defined copy constructor. o A copy constructor cannot be generated for that class. The order in which arguments are evaluated and passed to the function is implementation-defined. For example, the following sequence of statements calls the function tester: int x; x = 1; tester(x++, x); The call to tester in the preceding example may produce different results on different compilers. Depending on the implementation, x++ may be evaluated first or x may be evaluated first. To avoid ambiguity, if you want x++ to be evaluated first, you can replace the preceding sequence of statements with the following: int x, y; x = 1; y = x++; tester(y, x); Examples of Calling Functions and Passing Arguments Related Information o Passing Arguments by Reference o -- Reference cplr376 not found -- o Member Functions o Function Declarator o Function Declarations o Function Definition o Types ═══ Examples of Calling Functions ═══ /************************************************************************ * The following statement calls the function startup and passes no parameters: startup(); The following function call causes copies of a and b to be stored in a local area for the function sum. The function sum is executed using the copies of a and b. sum(a, b); The following function call passes the value 2 and the value of the expression a +b to sum: sum(2, a + b); The following statement calls the functions printf and sum. sum receives the values of a and b. printf receives a character string and the return value of the function sum: printf("sum = %d\n", sum(a,b)); The following program passes the value of count to the function increment. increment increases the value of the parameter x by 1. * ************************************************************************/ #include void increment(int); int main(void) { int count = 5; /* value of count is passed to the function */ increment(count); printf("count = %d\n", count); } void increment(int x) { ++x; printf("x = %d\n", x); } /************************************************************************ * The output illustrates that the value of count in main remains unchanged: x = 6 count = 5 In the following program, main passes the address of count to increment. The function increment was changed to handle the pointer. The parameter x is declared as a pointer. The contents to which x points are then incremented. * ************************************************************************/ #include int main(void) { void increment(int *x); int count = 5; /* address of count is passed to the function */ increment(&count); printf("count = %d\n", count); } void increment(int *x) { ++*x; printf("*x = %d\n", *x); } /************************************************************************ * The output shows that the variable count is increased: *x = 6 count = 6 * ************************************************************************/ ═══ 6.5.1. Passing Arguments by Reference ═══ If you use a reference type as a formal argument, you can make a pass-by-reference call to a function. In a pass-by-reference call, the values of arguments in the calling function can be modified in the called function. In pass-by-value calls, only copies of the arguments are passed to the function. Note: The term pass by reference describes a general method of passing arguments from a calling routine to a called routine. The term reference in the context of C++ refers to a specific way of declaring objects and functions. Example of Passing Arguments by Reference Arguments by reference in the following two cases causes the compiler to issue a warning: o Ellipsis arguments cannot be passed as references. o If the last argument specified in the function declaration before the ellipsis is a reference argument, arguments passed using an ellipsis (variable arguments) are not accessible using the mechanism from the standard header file. In addition, when the actual argument cannot be referenced directly by the formal argument, the compiler creates a temporary variable that is referenced by the formal argument and initialized using the value of the actual argument. In this case, the formal argument must be a .const reference. Reference arguments declared const can be used to pass large objects efficiently to functions without making a temporary copy of the object that is passed to the function. Because the reference is declared const, the actual arguments cannot be changed by the function. For example: void printbig (const bigvar&); // Function prototype When a function printbig is called, it cannot modify the object of type bigvar because the object was passed by constant reference. Related Information o Calling Functions and Passing Arguments o References o volatile and const Qualifiers ═══ Example of Passing Arguments by Reference ═══ /************************************************************************ * The following example shows how arguments are passed by reference. Note that reference formal arguments are initialized with the actual arguments when the function is called. * ************************************************************************/ #include void swapnum(int &i, int &j) { int temp = i; i = j; j = temp; } // . // . // . main() { int a = 10, // a is 10 b = 20; // b is 20 swapnum(a,b); // now a is 20 and b is 10 cout << "A is : " << a << " and B is : " << b << endl; } /************************************************************************ * When the function swapnum() is called, the actual values of the variables a and b are exchanged because they are passed by reference. The output is: A is : 20 and B is : 10 You must define the formal arguments of swapnum() as references if you want the values of the actual arguments to be modified by the function swapnum(). * ************************************************************************/ ═══ 6.6. Default Arguments ═══ In C++, you can provide default values for function arguments. All default argument names of a function are bound when the function is declared. All functions have their types checked at declaration, and are evaluated at each point of call. For example: #include int a = 1; int f(int a) {return a;} int g(int x = f(a)) {return f(a);} int h() { a=2; { int a = 3; return g(); } } main() { cout << h() << endl; } This example prints "2" to standard output, because the a referred to in the declaration of g() is the one at file scope, which has the value 2 when g() is called. The value of a is determined after entry into function h() but before the call to g() is resolved. A default argument can have any type. A pointer to a function must have the same type as the function. Attempts to take the address of a function by reference without specifying the type of the function produce an error. The type of a function is not affected by arguments with default values. The following example shows that the fact that a function has default arguments does not change its type. The default argument allows you to call a function without specifying all of the arguments, it does not allow you to create a pointer to the function that does not specify the types of all the arguments. Thus, f can be called without an explicit argument, but the pointer badpointer cannot be defined without specifying the type of the argument. int f(int = 0); void g() { int a = f(1); // ok int b = f(); // ok, default argument used } int (*pointer)(int) = &f; // ok, type of f() specified (int) int (*badpointer)() = &f; // error, badpointer and f have // different types. badpointer must // be initialized with a pointer to // a function taking no arguments. Additional information is provided on: o Restrictions on Default Arguments o Evaluating Default Arguments Related Information o Calling Functions and Passing Arguments o Functions ═══ 6.6.1. Restrictions on Default Arguments ═══ Of the operators, only the function call operator and the operator new can have default arguments when they are overloaded. Arguments with default values must be the trailing arguments in the function declaration argument list. For example: void f(int a, int b = 2, int c = 3); // trailing defaults void g(int a = 1, int b = 2, int c); // error, leading defaults void h(int a, int b = 3, int c); // error, default in middle Once a default argument has been given in a declaration or definition, you cannot redefine that argument, even to the same value. However, you can add default arguments not given in previous declarations. For example, the last declaration below attempts to redefine the default values for a and b: void f(int a, int b, int c=1); // valid void f(int a, int b=1, int c); // valid, add another default void f(int a=1, int b, int c); // valid, add another default void f(int a=1, int b=1, int c=1); // error, redefined defaults You can supply any default argument values in the function declaration or in the definition. All subsequent arguments must have default arguments supplied in this or a previous declaration of the function. You cannot use local variables in default argument expressions. For example, the compiler generates errors for both function g() and function h() below: void f(int a) { int b=4; void g(int c=a); // Local variable "a" inaccessible void h(int d=b); // Local variable "b" inaccessible } ═══ 6.6.2. Evaluating Default Arguments ═══ When a function defined with default arguments is called with trailing arguments missing, the default expressions are evaluated. For example: void f(int a, int b = 2, int c = 3); // declaration // ... int a = 1; f(a); // same as call f(a,2,3) f(a,10); // same as call f(a,10,3) f(a,10,20); // no default arguments Default arguments are checked against the function declaration and evaluated when the function is called. The order of evaluation of default arguments is undefined. Default argument expressions cannot use formal arguments of a function. For example: int f(int q = 3, int r = q); // error The argument r cannot be initialized with the value of the argument q because the value of q may not be known when it is assigned to r. If the above function declaration is rewritten: int q=5; int f(int q = 3, int r = q); // error the value of r in the function declaration still produces an error because the variable q defined outside of the function is hidden by the argument q declared for the function. Similarly: typedef double D; int f(int D, int z = D(5.3) ); // error Here the type D is interpreted within the function declaration as the name of an integer. The type D is hidden by the argument D. The cast D(5.3) is therefore not interpreted as a cast because D is the name of the argument not a type. In the following example, the nonstatic member a cannot be used as an initializer because a does not exist until an object of class X is constructed. You can use the static member b as an initializer because b is created independently of any objects of class X. You can declare the member b after its use as a default argument because the default values are not analyzed until after the final bracket } of the class declaration. class X { int a; f(int z = a) ; // error g(int z = b) ; // valid static int b; }; You must put parentheses around default argument expressions that contain template references. In the following example: class C { void f(int i = X&cs.y); }; the compiler cannot tell that the < represents the start of a template argument list and not the less than operator because the default argument X&cs.y cannot be processed until the end of the class. To avoid error messages, put parentheses around the expression containing the default argumement list: class C { void f( int i = (X&cs.y) ); }; ═══ 6.7. Return Values ═══ A value must be returned from a function unless the function has a return type of void. The return value is specified in a return statement. The following code fragment shows a function definition, including the return statement: int add(int i, int j) { return i + j; // return statement } The function add() can be called as shown in the following code fragment: int a = 10, b = 20; int answer = add(a, b); // answer is 30 In this example, the return statement initializes a variable of the returned type. The variable answer is initialized with the int value 30. The type of the returned expression is checked against the returned type. All standard and user-defined conversions are performed as necessary. The following return statements show different ways of returning values to a caller: return; // Returns no value return result; // Returns the value of result return 1; // Returns the value 1 return (x * x); // Returns the value of x * x Other than main(), if a function that does not have type void returns without a value (as in the first return statement shown in the example above) the compiler issues a warning message, and the result returned is undefined. Each time a function is called, new copies of its local variables are created. Because the storage for a local variable may be reused after the function has terminated, a pointer to a local variable or a reference to a local variable should not be returned. If a class object is returned, a temporary object may be created if the class has copy constructors or a destructor. References can also be used as return types for functions. The reference returns the lvalue of the object to which it refers. This allows you to place function calls on the left side of assignment statements. Referenced return values are used when assignment operators and subscripting operators are overloaded so that the results of the overloaded operators can be used as actual values. Related Information o return o Calling Functions and Passing Arguments o main o Temporary Objects o Special Overloaded Operators ═══ 6.8. Inline Functions ═══ Inline functions are used to reduce the overhead of a normal function call. A function is declared inline by using the specifier inline for C++ functions or _Inline for C functions. The inline specifier is a suggestion to the compiler that an inline expansion can be performed. Instead of transferring control to and from the function code segment, a modified copy of the function body may be substituted directly for the function call. An inline function can be declared and defined simultaneously. If it is declared with the keyword inline or _Inline, it can be declared without a definition. The following code fragment shows an inline function definition. Note that the definition includes both the declaration and body of the inline function. inline int add(int i, int j) { return i + j; } Both member and nonmember functions can be inline, and both have internal linkage. The use of the inline specifier does not change the meaning of the function. The inline expansion of a function may not preserve the order of evaluation of the actual arguments. For more information on inlining, see the Programming Guide. Related Information o Inline Specifiers o Inline Member Functions o Functions ═══ 6.9. Resolving Ambiguous Statements ═══ There are situations where a statement can be parsed as both a declaration and as an expression. Specifically, a function declaration can look like a function call in certain cases. The compiler resolves these ambiguities by applying the following rules: o If the statement can be parsed as a declaration but there are no declaration specifiers in the declaration and the statement is inside the body of a function, the statement is assumed to be an expression. The following statement, for example, is a declaration at file scope of the function f() that returns type int. There is no declaration specifier and int is the default, but at function scope this is a call to f(): f(); o If the statement can be parsed as a declaration up to the end of the first declarator, it is assumed to be a declaration even if subsequent parsing reveals that the statement is only valid as an expression. The following statement, for example, looks like a declaration with a syntax error at ++. Because it is a valid declaration for the first declarator (x), this statement is parsed as a declaration even though it could be parsed as a valid expression: int (x), y++; o In every other case, if the statement can be parsed as a declaration, it is assumed to be a declaration. The following statement, for example, is a declaration of x with redundant parentheses around the declarator, not a function-style cast of x to type int: int (x); In some cases, the C++ grammar does not disambiguate between expression statements and declaration statements. The ambiguity arises when an expression statement has a function-style cast as its leftmost subexpression. (Note that, because C does not support function-style casts, this ambiguity does not occur in C programs.) In some cases, the ambiguity can be resolved by examining the entire statement containing the expression or declaration. If the statement can be interpreted both as a declaration and as an expression, the statement is interpreted as a declaration statement. The following expressions disambiguate into expression statements because the ambiguous subexpression is followed by an assignment or an operator. T in the expressions can be any type specifier: T(i)++; T(i,3)<l=24; In the following examples, the ambiguity cannot be resolved so the statements are interpreted as declarations. T is any type specifier: T(*i)(int); T(j)[5]; T(*k) (float(3)); The last statement above causes a compile-time error because you cannot initialize a pointer with a float value. Any statement whose ambiguity is not resolved by the above rules is by default a declaration statement. All of the following are declaration statements: T(a); T(*b)(); T(c)=23; T(d),e,f,g=0; T(h)(e,3); The ambiguity is resolved only on a syntactic level. The disambiguation does not use the meaning of the names, except to assess whether or not they are type names. Another C++ ambiguity between expression statements and declaration statements is resolved by requiring a type name for function declarations within a block: a(); // declaration of a function returning int // and taking no arguments void func() { int a(); // declaration of a function int b; // declaration of a variable a(); // expression-statement calling function a() b; // expression-statement referring to a variable } The last statement above does not produce any action. It is semantically equivalent to a null statement. However, it is a valid C++ statement. Related Information o Function Declarations o Cast Expressions ═══ 7. Expressions and Operators ═══ This section describes C and C++ language expressions. Expressions are sequences of operators, operands, and punctuators that specify a computation. The evaluation of expressions is based on the operators that the expressions contain and the context in which they are used: o Primary Expression o Unary Expression o Binary Expression o Conditional Expression ? : o Assignment Expression o Comma Expression , o Lvalue o Constant Expression An expression can result in an lvalue, rvalue, or no value, and can produce side effects in each case. Note: C++ operators can be defined to behave differently when applied to operands of class type. This is called operator overloading. See Overloading Operators for more details. This section describes the behavior of operators that are not overloaded. The C language does not permit overloading. Operator Precedence shows the order of evaluation of the expressions and operators. Most expressions can contain several different, but related, types of operands. The following type classes describe related types of operands: Integral Character objects and constants, objects having an enumeration type, and objects having the type short, int, long, unsigned short, unsigned int, or unsigned long. Arithmetic Integral objects and objects having the type float, double, and long double. Scalar Arithmetic objects and pointers to objects of any type. Also C++ references. Aggregate Arrays, structures, and unions. Also C++ classes. Many operators cause conversions from one data type to another. Conversions are discussed in Conversions. ═══ 7.1. Operator Precedence ═══ Two operator characteristics determine how operands group with operators: precedence and associativity. Precedence provides a priority system for grouping different types of operators with their operands. Associativity provides a left-to-right or right-to-left order for grouping operands to operators that have the same precedence. For example, in the following statements, the value of 5 is assigned to both a and b because of the right-to-left associativity of the = operator. The value of c is assigned to b first, and then the value of b is assigned to a. b = 9; c = 5; a = b = c; Because the order of expression evaluation is not specified, you can explicitly force the grouping of operands with operators by using parentheses. In the expression a + b * c / d, the * and / operations are performed before + because of precedence. b is multiplied by c before it is divided by d because of associativity. The primary operators have the highest precedence. Table of Operator Precedence and Associativity lists the C and C++ language operators in order of precedence and shows the direction of associativity for each operator. In C++, the primary scope operator has the highest precedence, followed by the other primary operators. In C, because there is no scope operator, the other primary operators have the highest precedence. The comma operator has the lowest precedence. Operators that appear in the same group have the same precedence. The order of evaluation for function call arguments or for the operands of binary operators is not specified. Avoid writing such ambiguous expressions as: z = (x * ++y) / func1(y); func2(++i, x[i]); In the example above, the order of evaluation of ++y and func1(y) is not defined. If y had the value of 1 before the first statement, it is not known whether or not the value of 1 or 2 is passed to func1(). In the second statement, if i had the value of 1, it is not known whether the first or second array element of x[ ] is passed as the second argument to func2(). Do not write code that depends on a particular order of evaluation of operators with the same precedence. The order of grouping operands with operators in an expression containing more than one instance of an operator with both associative and commutative properties is not specified. The operators that have the same associative and commutative properties are: *, +, &, |, and ^ (or к). The grouping of operands can be forced by grouping the expression in parentheses. Examples of Expressions and Precedence Related Information o Parenthesized Expression ( ) o Expressions and Operators o Table of Operator Precedence and Associativity ═══ Examples of Expressions and Precedence ═══ The parentheses in the following expressions explicitly show how the C language groups operands and operators. If parentheses did not appear in these expressions, the operands and operators would be grouped in the same manner as indicated by the parentheses. total = (4 + (5 * 3)); total = (((8 * 5) / 10) / 3); total = (10 + (5/3)); The following expression contains operators that are both associative and commutative: total = price + prov_tax + city_tax; Because the C language does not specify the order of grouping operands with operators that are both associative and commutative, the operands and operators could be grouped in the following ways (as indicated by parentheses): total = (price + (prov_tax + city_tax)); total = ((price + prov_tax) + city_tax); total = ((price + city_tax) + prov_tax); However, the grouping of operands and operators could affect the result. In the following expression, each function call may be modifying the same global variables. These side effects may result in different values for the expression depending on the order in which the functions are called: a = b() + c() + d(); If the expression contains operators that are both associative and commutative and the order of grouping operands with operators can affect the result of the expression, separate the expression into several expressions. For example, the following expressions could replace the previous expression if the called functions do not produce any side effects that affect the variable a. a = b(); a += c(); a += d(); ═══ 7.1.1. Table of Operator Precedence and Associativity ═══ Operator Name Operators Primary scope :: Associativity: left to right Primary () [ ] . -> Associativity: left to right Unary ++ -- - + ! ~ & * sizeof new delete (typename) (C cast) Associativity: right to left C++ Cast (typename) Associativity: left to right C++ Pointer to Member .* ->* Associativity: left to right Multiplicative * / % Associativity: left to right Additive + - Associativity: left to right Bitwise Shift << >> Associativity: left to right Relational < > <= >= Associativity: left to right Equality == != Associativity: left to right Bitwise Logical AND & Associativity: left to right Bitwise Exclusive OR ^ or к Associativity: left to right Bitwise Inclusive OR | Associativity: left to right Logical AND && Associativity: left to right Logical OR || Associativity: left to right Conditional ? : Associativity: right to left Assignment = += -= *= /= <<= >>= %= &= ^= |= Associativity: right to left Comma , Associativity: left to right ═══ 7.2. Lvalue ═══ An lvalue is an expression that represents an object. A modifiable lvalue is an expression representing an object that can be changed. A modifiable lvalue is the left operand in an assignment expression. However, arrays and const objects are not modifiable lvalues. All assignment operators evaluate their right operand and assign that value to their left operand. The left operand must evaluate to a reference to an object. The assignment operators are not the only operators that require an operand to be an lvalue. The address operator requires an lvalue as an operand while the increment and the decrement operators require a modifiable lvalue as an operand. Examples of Lvalues Related Information o Assignment Expression o Address & o Dot Operator o Arrow Operator ═══ Examples of Lvalues ═══ Expression Lvalue x = 42; x *ptr = newvalue; *ptr a++ a ═══ 7.3. Constant Expression ═══ A constant expression is an expression with a value that is determined during compilation and cannot be changed during execution. It can only be evaluated. Constant expressions can be composed of integer constants, character constants, floating-point constants, and enumeration constants. The C and C++ languages require constant expressions in the following places: o In the subscript declarator, as the description of an array bound o After the keyword case in a switch statement o In an enumerator, as the numeric value of an enum constant o In a bit-field width specifier o In the preprocessor if statement o In the initializer of a file scope data definition. In all the cases above, except for an initializer of a file scope data definition, the constant expression can contain integer, character, and enumeration constants, casts to integral types, and sizeof expressions. In a file scope data definition, the initializer must evaluate to a constant or to the address of a static storage (extern or static) object (plus or minus an integer constant) that is defined or declared earlier in the file. Thus, the constant expression in the initializer can contain integer, character, enumeration, and float constants, casts to any type, sizeof expressions, and addresses (possibly modified by constants) of static objects. Functions, class objects, pointers, and references are not allowed unless they occur in sizeof expressions. Comma operators and assignment operators cannot appear in constant expressions. Examples of Constant Expressions Related Information o Arrays o Initializers o File Scope Data Declarations o switch o Enumerations o Structures o Conditional Compilation o sizeof (Size of an Object) ═══ Examples of Constant Expressions ═══ The following examples show constants used in expressions. Expression Constant x = 42; 42 extern int cost = 1000; 1000 y = 3 * 29; 3 * 29 ═══ 7.4. Primary Expression ═══ A primary expression can be: o Identifiers o Strings o Scope Resolution Operator o Parenthesized Expression ( ) o Constant Expression o Function Call ( ) o Array Subscript [ ] o Dot Operator o Arrow Operator All primary operators have the same precedence and have left-to-right associativity. Related Information o Expressions and Operators o Operator Precedence ═══ 7.4.1. Scope Resolution Operator ═══ The :: (scope resolution) operator is used to qualify hidden names so that you can still use them. You can use the unary scope operator if a file scope name is hidden by an explicit declaration of the same name in a block or class. For example: int i = 10; int f(int i) { return i ? i : :: i; // return global i if local i is zero } You can also use the class scope operator to qualify class names or class member names. If a class member name is hidden, you can use it by qualifying it with its class name and the class scope operator. Whenever a name is followed by a :: operator, the name is interpreted as a class name. In the following example, the declaration of the variable X hides the class type X, but you can still use the static class member count by qualifying it with the class type X and the scope resolution operator. #include class X { public: static int count; }; int X::count = 10; // define static data member void main () { int X = 0; // hides class type X cout << X::count << endl; // use static member of class X } The scope resolution operator is also discussed in Class Names and in Scope of Class Names. Related Information o Class Names o Scope of Class Names o Expressions and Operators ═══ 7.4.2. Parenthesized Expression ( ) ═══ You can use parentheses to explicitly force the order of expression evaluation. The following expression does not contain any parentheses used for grouping operands and operators. The parentheses surrounding weight, zipcode are used to form a function call. Notice how the operands and operators are grouped in this expression according to the rules for operator precedence and associativity: -discount * item + handling(weight, zipcode) < .10 * item │ │ │ │ │ │ │ └───┬───┘ │ └───────────┬───────────┘ └────┬───┘ └────┬─────┘ │ │ └──────────┬──────────┘ │ └───────────────────────────────┘ The following expression is similar to the previous expression. This expression, however, contains parentheses that change how the operands and operators group: (-discount * (item + handling(weight, zipcode) ) ) < (.10 * item) │ │ │ │ │ │ │ └───┬───┘ │ └──────────┬────────────┘ └─────┬────┘ │ └────────┬────────┘ │ └───────┬─────────┘ │ └─────────────────────────────────────────────┘ In an expression that contains both associative and commutative operators, you can use parentheses to specify the grouping of operands with operators. The parentheses in the following expression guarantee the order of grouping operands with the operators: x = f + (g + h); Related Information o Operator Precedence o Function Call ( ) o Expressions and Operators ═══ 7.4.3. Function Call ( ) ═══ A function call is a primary expression containing a parenthesized argument list. The argument list can contain any number of expressions separated by commas. For example: stub() overdue(account, date, amount) notify(name, date + 5) report(error, time, date, ++num) The arguments are evaluated, and each parameter is assigned the value of the corresponding argument. Assigning a value to a parameter within the function body changes the value of the parameter within the function, but has no effect on the argument. When you define a function as returning a certain type, for example type int, the result of the function call has that type. If you want a function to change the value of a variable, pass a pointer to the variable you want changed. When a pointer is passed as a parameter, the pointer is copied; the object pointed to is not copied. (See Pointers.) All arrays and functions are converted to pointers when passed as function arguments. Arguments passed to nonprototyped functions undergo conversions: type short or char parameters will be converted to int, and float parameters to double. Use a cast expression for other conversions. (See Cast Expressions.) If the function has not been previously declared, an implicit declaration of extern int func(); is assumed. The compiler compares the data types provided by the calling function with the data types that the called function expects. The compiler may also perform type conversions if the declaration of the function is in function prototype format and the parameters differ from the prototype or visible at the point where the function is called. The order in which parameters are evaluated is not specified. Avoid such calls as: method(samp1, bat.proc--, bat.proc); In the preceding example, bat.proc-- may be evaluated last, causing the last two arguments to be passed with the same value. A function can call itself. Example of a Function Call Related Information o Functions o Pointers o Cast Expressions o Primary Expression ═══ Example of a Function Call ═══ /************************************************************************ * In the following example, main passes func two values: 5 and 7. The function func receives copies of these values and accesses them by the identifiers: a and b. The function func changes the value of a. When control passes back to main, the actual values of x and y are not changed. The called function func only receives copies of x and y, not the values themselves. * ************************************************************************/ #include int main(void) { int x = 5, y = 7; func(x, y); printf("In main, x = %d y = %d\n", x, y); } void func (int a, int b) { a += b; printf("In func, a = %d b = %d\n", a, b); } /************************************************************************ * The preceding program produces the following output: In func, a = 12 b = 7 In main, x = 5 y = 7 * ************************************************************************/ ═══ 7.4.4. Array Subscript [ ] ═══ A primary expression followed by an expression in [ ] (square brackets) specifies an element of an array. The expression within the square brackets is referred to as a subscript. The primary expression must have a pointer type, and the subscript must have integral type. The result of an array subscript is an lvalue. The first element of each array has the subscript 0. Thus, the expression contract[35] refers to the 36th element in the array contract. In a multidimensional array, you can reference each element (in the order of increasing storage locations) by incrementing the rightmost subscript most frequently. For example, the following statement gives the value 100 to each element in the array code[4][3][6]: for (first = 0; first <= 3; ++first) for (second = 0; second <= 2; ++second) for (third = 0; third <= 5; ++third) code[first][second][third] = 100; Related Information o Arrays o Lvalue o Primary Expression ═══ 7.4.5. Dot Operator ═══ The . (dot) operator is a class access member operator that is used to access class members using a class object. A primary expression, followed by a . (dot) operator, followed by a name, designates a member of a class object. For example: roster[num].name roster[num].name[1] The primary expression must be a class object. Note that class objects can be of type class, struct, or union. The name must be a member of that class object. The value of the expression is the value of the selected member. If the primary expression and the name are lvalues, the expression value is also an lvalue. For more information on class members, see C++ Class Members and Friends. Related Information o Arrow Operator o C++ Class Members and Friends o Unions o Structures o Lvalue o Primary Expression ═══ 7.4.6. Arrow Operator ═══ The -> (arrow) operator is a class access member operator that is used to access class members using a pointer. A primary expression, followed by an -> (arrow) operator, followed by a name, designates a member of the object to which the pointer points. For example: roster -> name The primary expression must be a pointer to a class object. Note that class objects can be of type class, struct, or union. The name must be a member of that class object. The value of the expression is the value of the selected member. If the name is an lvalue, the expression value is also an lvalue. For more information on class members, see C++ Class Members and Friends. Related Information o Dot Operator o C++ Class Members and Friends o Unions o Structures o Lvalue o Pointers o Primary Expression ═══ 7.5. Unary Expression ═══ A unary expression contains one operand and a unary operator. All unary operators have the same precedence and have right-to-left associativity. o Increment ++ o Decrement - - o Unary Plus + o Unary Minus - o Logical Negation ! o Bitwise Negation ~ o Address & o Indirection * o Cast Expressions o sizeof (Size of an Object) o new Operator o delete Operator o throw Expressions Related Information o Binary Expression o Expressions and Operators o Operator Precedence ═══ 7.5.1. Increment ++ ═══ The ++ (increment) operator adds 1 to the value of the scalar operand, or if the operand is a pointer, increments the operand by the size of the object to which it points. The operand receives the result of the increment operation. Thus, the operand must be a modifiable lvalue. You can place the ++ before or after the operand. If it appears before the operand, the operand is incremented. Then the incremented value is used in the expression. If you place the ++ after the operand, the current value of the operand is used in the expression. Then the operand is incremented. For example: play = ++play1 + play2++; is equivalent to the following three expressions: play1 = play1 + 1; play = play1 + play2; play2 = play2 + 1; The type of the increment expression is the same type as that of the operand. Related Information o Decrement - - o Addition + o Pointer Arithmetic o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.2. Decrement - - ═══ The -- (decrement) operator subtracts 1 from the value of the scalar operand, or if the operand is a pointer, decreases the operand by the size of the object to which it points. The operand receives the result of the decrement operation. Thus, the operand must be a modifiable lvalue. You can place the -- before or after the operand. If it appears before the operand, the operand is decremented, and the decremented value is used in the expression. If the -- appears after the operand, the current value of the operand is used in the expression and the operand is decremented. For example: play = --play1 + play2--; is equivalent to the following three expressions: play1 = play1 - 1; play = play1 + play2; play2 = play2 - 1; The type of the decrement expression is the same type as that of the operand. Related Information o Increment ++ o Subtraction - o Pointer Arithmetic o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.3. Unary Plus + ═══ The + (unary plus) operator maintains the value of the operand. The operand can have any arithmetic type. The result is not an lvalue. The result of the unary plus expression has the same type as the operand after any integral promotions (for example, char to int). Note: Any plus sign preceding a constant is not part of the constant. Related Information o Unary Minus - o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.4. Unary Minus - ═══ The - (unary minus) operator negates the value of the operand. The operand can have any arithmetic type. The result is not an lvalue. For example, if quality has the value 100, -quality has the value -100. The result of the unary minus expression has the same type as the operand after any integral promotions (for example, char to int). Note: Any minus sign preceding a constant is not part of the constant. Related Information o Unary Plus + o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.5. Logical Negation ! ═══ The ! (logical negation) operator determines whether the operand evaluates to 0 (false) or nonzero (true). The expression yields the value 1 (true) if the operand evaluates to 0, and yields the value 0 (false) if the operand evaluates to a nonzero value. The operand must have a scalar data type, but the result of the operation has always type int and is not an lvalue. The following two expressions are equivalent: !right; right == 0; Related Information o Equality == != o Relational < > <= >= o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.6. Bitwise Negation ~ ═══ The ~ (bitwise negation) operator yields the bitwise complement of the operand. In the binary representation of the result, every bit has the opposite value of the same bit in the binary representation of the operand. The operand must have an integral type. The result has the same type as the operand but is not an lvalue. Suppose x represents the decimal value 5. The 16-bit binary representation of x is: 0000000000000101 The expression ~x yields the following result (represented here as a 16-bit binary number): 1111111111111010 Note that the ~ character can be represented by the trigraph ??-. The 16-bit binary representation of ~0 is: 1111111111111111 Related Information o Bitwise Left and Right Shift << >> o Bitwise AND & o Bitwise Exclusive OR ^ o Bitwise Inclusive OR | o Unary Expression o Usual Arithmetic Conversions ═══ 7.5.7. Address & ═══ The & (address) operator yields a pointer to its operand. The operand must be an lvalue, a function designator, or a qualified name. It cannot be a bit field, nor can it have the storage class specifier register. If the operand is an lvalue or function, the resulting type is a pointer to the expression type. For example, if the expression has type int, the result is a pointer to an object having type int. If the operand is a qualified name and the member is not static, the result is a pointer to a member of class and has the same type as the member. The result is not an lvalue. If p_to_y is defined as a pointer to an int and y as an int, the following expression assigns the address of the variable y to the pointer p_to_y: p_to_y = &y; You can use the & operator with overloaded functions only in an initialization or assignment where the left side uniquely determines which version of the overloaded function is used. For more information, see Overloading Functions. Related Information o Pointers o Lvalue o register Storage Class Specifier o Overloading Functions o Unary Expression ═══ 7.5.8. Indirection * ═══ The * (indirection) operator determines the value referred to by the pointer-type operand. The operand cannot be a pointer to void. The operation yields an lvalue or a function designator if the operand points to a function. Arrays and functions are converted to pointers. The type of the operand determines the type of the result. Thus, if the operand is a pointer to an int, the result has type int. Do not apply the indirection operator to any pointer that contains an address that is not valid, such as NULL. The result of applying an indirection operator to such a pointer is not defined. If p_to_y is defined as a pointer to an int and y as an int, the expressions: p_to_y = &y; *p_to_y = 3; cause the variable y to receive the value 3. Related Information o Pointers o Lvalue o Functions o Unary Expression ═══ 7.5.9. Cast Expressions ═══ The cast operator is used for explicit type conversions. The () (cast) operator converts the value of the operand to a specified data type and performs the necessary conversions to the operand for the type. For C, the operand must be scalar and the type must be either scalar or void. For C++, the operand can have class type. If the operand has class type, it can be cast to any type for which the class has a user-defined conversion function. User-defined conversion functions are described in Conversion Functions. The result of a cast is not an lvalue unless the cast is to a reference type. When you cast to a reference type, no user-defined conversions are performed and the result is an lvalue. There are two types of casts that take one argument: o C-style casts, with the format (X)a. These are the only casts allowed in C. o function-style casts with one argument, such as X(a) These are allowed in C++ only. Both types of casts convert the argument a to the type X. They can invoke a constructor, if the target type is a class, or they can invoke a conversion function, if the source type is a class. They can be ambiguous if both conditions hold. A function-style cast with no arguments, such as X(), creates a temporary object of type X. If X is a class with constructors, the default constructor X::X() is called. A function-style cast with more than one argument, such as X(a,b), creates a temporary object of type X. This object must be a class with a constructor that takes two arguments of types compatible with the types of a and b. The constructor is called with a and b as arguments. Related Information o Conversions o Conversion by Constructor o Conversion Functions o Types ═══ 7.5.10. sizeof (Size of an Object) ═══ The sizeof operator yields the size in bytes of the operand. The sizeof operation cannot be performed on a bit field, a function, an undefined class, an array with unspecified dimensions, or an incomplete type such as void. The operand may be the parenthesized name of a type. The compiler must be able to evaluate the size at compile time. The expression is not evaluated; there are no side effects. For example, the value of b is 5 from initialization to program termination: #include int main(void){ int b = 5; sizeof(b++); } The size of a char object is the size of a byte. Given that the variable x has type char, the expression sizeof(x) always evaluates to 1. The result of a sizeof operation has type size_t. size_t is an unsigned integral type defined in the header. The compiler determines the size of an object on the basis of its definition. The sizeof operator does not perform any conversions. However, if the operand contains operators that perform conversions, the compiler takes these conversions into consideration. The following expression causes the usual arithmetic conversions to be performed. The result of the expression x + 1 has type int (if x has type char, short, or int or any enumeration type) and is equivalent to sizeof(int): sizeof (x + 1) When you perform the sizeof operation on an array, the result is the total number of bytes in the array. The compiler does not convert the array to a pointer before evaluating the expression. When you perform the sizeof operation on a class, the result is always nonzero and is equal to the number of bytes in an object of that class including any padding required for placing class objects in an array. When you perform the sizeof operation on a reference, the result is the size of the referenced object. You can use a sizeof expression wherever a constant or unsigned constant is required. One of the most common uses for the sizeof operator is to determine the size of objects that are being communicated to or from storage allocation, input, and output functions. For portability of code, you should use the sizeof operator to determine the size that a data type represents. In this instance, the name of the data type must be placed in parentheses after the sizeof operator. For example: sizeof(int) Related Information o Constant Expression o Conversions o Types o Unary Expression ═══ 7.5.11. new Operator ═══ The new operator provides dynamic storage allocation. The syntax for an allocation expression containing the new operator is: >>──┬────┬──new──┬─────────────────┬──┬─(type)───┬─────────────────────────────> └─::─┘ └─(argument_list)─┘ └─new_type─┘ >──┬─────────────────────────┬────────────────────────────────────────────────>< └─(──┬───────────────┬──)─┘ └─initial_value─┘ If you prefix new with ::, the global operator new() is used. If you specify an argument_list, the overloaded new operator that corresponds to that argument_list is used. The type is an existing built-in or user-defined type. A new_type is a type that has not already been defined and can include type specifiers and declarators. An allocation expression containing the new operator is used to find storage in free store for the object being created. The new-expression returns a pointer to the object created and can be used to initialize the object. If the object is an array, a pointer to the initial element is returned. You can use the routine set_new_handler to change the default behavior of new. You can also use the /Tm option to enable the debug version of new, as described in Debug Versions of new and delete. You cannot use the new operator to allocate function types, void, or incomplete class types because these are not object types. However, you can allocate pointers to functions with the new operator. You cannot create a reference with the new operator. When the object being created is an array, only the first dimension can be a general expression. All subsequent dimensions must be constant integral expressions. The first dimension can be a general expression even when an existing type is used. You can create an array with zero bounds with the new operator. For example: char * c = new char[0]; In this case, a pointer to a unique object is returned. An object created with operator new() or operator new[]() exists until the operator delete() is called to deallocate the object's memory, or until program ends. If parentheses are used within a new_type, parentheses should also surround the new_type to prevent syntax errors. Example of Allocating Storage with new() The type of the object being created cannot include class declarations, enumeration declarations, or const or volatile types. It can include pointers to const or volatile objects. For example, const char* is allowed, but char* const is not. Additional arguments can be supplied to new by using the argument_list, also called the placement syntax. If placement arguments are used, a declaration of operator new() with these arguments must exist. For example: #include class X { public: void* operator new(size_t,int, int){ /* ... */ } }; void main () { X* ptr = new(1,2) X; } Additional information is provided on: o Member Functions and the Global operator new() o Initializing Objects Created with the new Operator Related Information o set_new_handler - Set Behavior for new Failure o Overloaded new and delete o Debug Versions of new and delete o Constructors and Destructors Overview o Free Store o delete Operator o Unary Expression ═══ Member Functions and the Global operator new() ═══ When an object of a class type is created with the new operator, the member operator new() function is implicitly called. The first argument is the amount of space requested. The following rules determine which storage allocation function is used: 1. If your own operator new() exists, and the :: operator is not used, your operator new() is used. 2. If you have not defined an operator new() function, the global ::operator new() function defined in is used. The allocation expression of the form ::operator new() ensures that the global new operator is called, rather than your class member operator. ═══ Initializing Objects Created with the new Operator ═══ You can initialize objects created with the new operator in several ways. For nonclass objects, or for class objects without constructors, a new-initializer expression can be provided in a new-expression by specifying ( expression ) or (). For example: double* pi = new double(3.1415926); int* score = new int(89); float* unknown = new float(); If a class has a constructor, the new-initializer must be provided when any object of that class is allocated. The arguments of the new-initializer must match the arguments of a class constructor, unless the class has a default constructor. You cannot specify an initializer for arrays. You can initialize an array of class objects only if the class has a default constructor. The constructor is called to initialize each array element (class object). Initialization using the new-initializer is performed only if new successfully allocates storage. ═══ Example of Allocating Storage with new() ═══ /*********************************************************************** * In the following example, storage is allocated for an array of pointers to functions: * ************************************************************************/ void f(); void g(); void main() { void (**p)(), (**q)(); // declare p and q as pointers to pointers to void functions p = new (void (*[3])()); // p now points to an array of pointers to functions q = new void(*[3])(); // error // error - bound as 'q = (new void) (*[3])();' p[0] = f; // p[0] to point to function f q[2] = g; // q[2] to point to function g p[0](); // call f() q[2](); // call g() } /************************************************************************ * However, the second use of new causes an erroneous binding of q = (new void) (*[3])(). * ************************************************************************/ ═══ 7.5.11.1. set_new_handler - Set Behavior for new Failure ═══ When the new operator creates a new object, it calls the operator new() function to obtain the needed storage. When new cannot allocate storage, it calls a new-handler function if one has been installed by a call to set_new_handler(). You can use the set_new_handler function, defined in , to call the default new-handler or one of your own. The set_new_handler function has the prototype: int set_new_handler(*function); If you do not specify your own set_new_handler function, new returns the NULL pointer. Example of set_new_handler Related Information o new Operator o Member Function and the Global operator new() o Initializing Objects Created with the new Operator o Overloaded new and delete o Constructors and Destructors Overview o Free Store ═══ Example of set_new_handler ═══ The following program segment shows how you could use set_new_handler to return a message if the new operator cannot allocate storage: #include #include void no_storage() { cerr << "Operator new failed: no storage is available.\n"; exit(1); } main() { set_new_handler(&no_storage); // Rest of program ... } If the program fails because new cannot allocate storage, the program exits with the message: Operator new failed: no storage is available. ═══ 7.5.12. delete Operator ═══ The delete operator destroys the object created with new by deallocating the memory associated with the object. The delete operator has a void return type. It has the syntax: >>──┬────┬──delete──object_pointer────────────────────────────────────────────>< └─::─┘ For example: delete myobj; The operand of delete must be a pointer returned by new, and cannot be a pointer to constant. If an attempt to create an object with new fails, the pointer returned by new will have a zero value, but it can still be used with delete. Deleting a null pointer has no effect. The delete[] operator frees storage allocated for array objects created with new.. The delete frees storage allocated for individual objects created with new. It has the syntax: >>──┬────┬──delete──[──]──array───────────────────────────────────────────────>< └─::─┘ For example: delete [] myarray; The result of deleting an array object with delete is undefined, as is deleting an individual object with delete[]. The array dimensions do not need to be specified with delete[]. The results of attempting to access a deleted object are undefined because the deletion of an object can change its value. If a destructor has been defined for a class, delete invokes that destructor. Whether a destructor exists or not, delete frees the storage pointed to by calling the function operator delete() of the class if one exists. The global ::operator delete() is used if: o The class has no operator delete(). o The object is of a nonclass type. o The object is deleted with the ::delete expression. For example: ::delete p; The default global operator delete() only frees storage allocated by the default global operator new(). The default global operator delete[]() only frees storage allocated for arrays by the default global operator new(). You can also use the /Tm compiler option to enable a debug version of the delete operator, as described in Debug Versions of new and delete. Related Information o Overloaded new and delete o Debug Versions of new and delete o Constructors and Destructors Overview o Free Store o new Operator o Unary Expression ═══ 7.5.13. throw Expressions ═══ A throw expression is used to throw exceptions to C++ exception handlers. It causes control to be passed out of the block enclosing the throw statement to the first C++ exception handler whose catch argument matches the throw expression. A throw expression is a unary expression of type void. For more information on the throw expression, see Exception Handling. Related Information o Exception Handling o Unary Expression ═══ 7.6. Binary Expression ═══ A binary expression contains two operands separated by one operator. Not all binary operators have the same precedence. The table in the section Operator Precedence shows the order of precedence among operators. All binary operators have left-to-right associativity. The order in which the operands of most binary operators are evaluated is not specified. Therefore, to ensure correct results, avoid creating binary expressions that depend on the order in which the compiler evaluates the operands. o Pointer to Member Operators .* ->* o Multiplication * o Division / o Remainder % o Addition + o Subtraction - o Bitwise Left and Right Shift << >> o Relational < > <= >= o Equality == != o Bitwise AND & o Bitwise Exclusive OR ^ o Bitwise Inclusive OR | o Logical AND && o Logical OR || Related Information o Unary Expression o Expressions and Operators o Operator Precedence ═══ 7.6.1. Pointer to Member Operators .* ->* ═══ The .* operator is used to dereference pointers to class members. The first operand must be a class type. If the type of the first operand is class type T, or is a class that has been derived from class type T, the second operand must be a pointer to a member of a class type T. The ->* operator is also used to dereference pointers to class members. The first operand must be a pointer to a class type. If the type of the first operand is a pointer to class type T, or is a pointer to a class derived from class type T, the second operand must be a pointer to a member of class type T. The .* and ->* operators bind the second operand to the first, resulting in an object or function of the type specified by the second operand. If the result of.* or ->* is a function, you can only use the result as the operand for the ( ) (function call) operator. If the second operand is an lvalue, the result of .* or ->* is an lvalue. For more information on pointer to member operators, see Pointers to Members. Related Information o Pointers to Members o Pointers o C++ Classes o Binary Expression ═══ 7.6.2. Multiplication * ═══ The * (multiplication) operator yields the product of its operands. The operands must have an arithmetic type. The result is not an lvalue. Because the multiplication operator has both associative and commutative properties, the compiler may rearrange the operands in an expression that contains more than one multiplication operator. For example, the expression: sites * number * cost can be interpreted in any of the following ways: (sites * number) * cost sites * (number * cost) (cost * sites) * number Related Information o Division / o Remainder % o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.3. Division / ═══ The / (division) operator yields the quotient of its operands. The operands must have an arithmetic type. The result is not an lvalue. If both operands are positive integers and the operation produces a remainder, the remainder is ignored. Thus, the expression 7 / 4 yields the value 1 (rather than 1.75 or 2). For SAA-compliant compilers, including the C/C++ Tools compiler, the result of -7 /4 is -1 with a remainder of -3, assuming both -7 and 4 are signed. If 4 is unsigned, -7 is converted to unsigned. The result is undefined if the second operand evaluates to 0. Related Information o Multiplication * o Remainder % o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.4. Remainder % ═══ The % (remainder) operator yields the remainder from the division of the left operand by the right operand. For example, the expression 5 % 3 yields 2. The result is not an lvalue. Both operands must have an integral type. If the right operand evaluates to 0, the result is undefined. If either operand has a negative value, the result is such that the following expression always yields the value of a if b is not 0 and a/b is representable: ( a / b ) * b + a % b; Related Information o Multiplication * o Division / o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.5. Addition + ═══ The + (addition) operator yields the sum of its operands. Both operands must have an arithmetic type, or the first operand must be a pointer to an object type and the other operand must have an integral type. When both operands have an arithmetic type, the usual arithmetic conversions on the operands are performed. The result has the type produced by the conversions on the operands and is not an lvalue. When one of the operands is a pointer, the compiler converts the other operand to an address offset. The result is a pointer of the same type as the pointer operand. Related Information o Pointers o Unary Plus + o Subtraction - o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.6. Subtraction - ═══ The - (subtraction) operator yields the difference of its operands. Both operands must have an arithmetic type, or the left operand must have a pointer type and the right operand must have the same pointer type or an integral type. When both operands have an arithmetic type, the usual arithmetic conversions on the operands are performed. The result has the type produced by the conversions on the operands and is not an lvalue. When the left operand is a pointer and the right operand has an integral type, the compiler converts the value of the right to an address offset. The result is a pointer of the same type as the pointer operand. If both operands are pointers to the same type, the compiler converts the result to an integral type that represents the number of objects separating the two addresses. Behavior is undefined if the pointers do not refer to objects in the same array. Related Information o Pointers o Unary Minus - o Addition + o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.7. Bitwise Left and Right Shift << >> ═══ The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted. The result is not an lvalue. The << (bitwise left shift) operator indicates the bits are to be shifted to the left. The >> (bitwise right shift) operator indicates the bits are to be shifted to the right. Each operand must have an integral type. The compiler performs integral promotions on the operands. Then the right operand is converted to type int. The result has the same type as the left operand (after the arithmetic conversions). If the right operand has a negative value or a value that is greater than or equal to the width in bits of the expression being shifted, the result is undefined. If the right operand has the value 0, the result is the value of the left operand (after the usual arithmetic conversions). The << operator fills vacated bits with zeros. For example, if l_op has the value 4019, the bit pattern (in 16-bit format) of l_op is: 0000111110110011 The expression l_op << 3 yields: 0111110110011000 If the left operand has an unsigned type, the >> operator fills vacated bits with zeros. Otherwise, the compiler will fill the vacated bits of a signed value with a copy of the value's sign bit. For example, if l_op has the value -25, the bit pattern (in 16-bit format) of l_op is: 1111111111100111 The expression l_op >> 3 yields: 1111111111111100 Related Information o Bitwise Negation ~ o Bitwise AND & o Bitwise Exclusive OR ^ o Bitwise Inclusive OR | o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.8. Relational < > <= >= ═══ The relational operators compare two operands and determine the validity of a relationship. If the relationship stated by the operator is true, the value of the result is 1. Otherwise, the value of the result is 0. The following table describes the relational operators: Operator Usage < Indicates whether the value of the left operand is less than the value of the right operand. > Indicates whether the value of the left operand is greater than the value of the right operand. <= Indicates whether the value of the left operand is less than or equal to the value of the right operand. >= Indicates whether the value of the left operand is greater than or equal to the value of the right operand. Both operands must have arithmetic types or be pointers to the same type. The result has type int. If the operands have arithmetic types, the usual arithmetic conversions on the operands are performed. When the operands are pointers, the result is determined by the locations of the objects to which the pointers refer. If the pointers do not refer to objects in the same array, the result is not defined. A pointer can be compared to a constant expression that evaluates to 0. You can also compare a pointer to a pointer of type void*. The pointer is converted to a pointer of type void*. If two pointers refer to the same object, they are considered equal. If two pointers refer to nonstatic members of the same object, the pointer to the object declared later has the higher address value. If two pointers refer to data members of the same union, they have the same address value. If two pointers refer to elements of the same array, or to the first element beyond the last element of an array, the pointer to the element with the higher subscript value has the higher address value. You can only compare members of the same object with relational operators. Relational operators have left-to-right associativity. Therefore, the expression: a < b <= c is interpreted as: (a < b) <= c If the value of a is less than the value of b, the first relationship is true and yields the value 1. The compiler then compares the value 1 with the value of c. Related Information o Equality == != o Logical Negation ! o Pointers o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.9. Equality == != ═══ The equality operators, like the relational operators, compare two operands for the validity of a relationship. The equality operators, however, have a lower precedence than the relational operators. If the relationship stated by an equality operator is true, the value of the result is 1. Otherwise, the value of the result is 0. The following table describes the equality operators: Operator Usage == Indicates whether the value of the left operand is equal to the value of the right operand. != Indicates whether the value of the left operand is not equal to the value of the right operand. Both operands must have arithmetic types or be pointers to the same type, or one operand must have a pointer type and the other operand must be a pointer to void or NULL. The result has type int. If the operands have arithmetic types, the usual arithmetic conversions on the operands are performed. If the operands are pointers, the result is determined by the locations of the objects to which the pointers refer. If one operand is a pointer and the other operand is an integer having the value 0, the expression is true only if the pointer operand evaluates to NULL. You can also use the equality operators to compare pointers to members that are of the same type but do not belong to the same object. Note: The equality operator (==) should not be confused with the assignment operator (=). For example, if(x == 3) evaluates to 1 if x is equal to three while if(x = 3) is taken to be true because (x = 3) evaluates to a non-zero value (3). The expression also assigns the value 3 to x. Related Information o Relational < > <= >= o Logical Negation ! o Pointers o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.10. Bitwise AND & ═══ The & (bitwise AND) operator compares each bit of its first operand to the corresponding bit of the second operand. If both bits are 1's, the corresponding bit of the result is set to 1. Otherwise, it sets the corresponding result bit to 0. Both operands must have an integral type. The usual arithmetic conversions on each operand are performed. The result has the same type as the converted operands. Because the bitwise AND operator has both associative and commutative properties, the compiler may rearrange the operands in an expression that contains more than one bitwise AND operator. The following example shows the values of a, b, and the result of a & b represented as 16-bit binary numbers: bit pattern of a 0000000001011100 bit pattern of b 0000000000101110 bit pattern of a & b 0000000000001100 Note: The bitwise AND (&) should not be confused with the logical AND (&&) operator. For example, 1 & 4 evaluates to 0 while 1 && 4 evaluates to 1 Related Information o Bitwise Exclusive OR ^ o Bitwise Inclusive OR | o Logical AND && o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.11. Bitwise Exclusive OR ^ ═══ The bitwise exclusive OR operator (in EBCDIC, the ^ symbol is represented by the к symbol) compares each bit of its first operand to the corresponding bit of the second operand. If both bits are 1's or both bits are 0's, the corresponding bit of the result is set to 0. Otherwise, it sets the corresponding result bit to 1. Both operands must have an integral type. The usual arithmetic conversions on each operand are performed. The result has the same type as the converted operands and is not an lvalue. Because the bitwise exclusive OR operator has both associative and commutative properties, the compiler may rearrange the operands in an expression that contains more than one bitwise exclusive OR operator. Note that the ^ character can be represented by the trigraph ??'. The following example shows the values of a, b, and the result of a ^ b represented as 16-bit binary numbers: bit pattern of a 0000000001011100 bit pattern of b 0000000000101110 bit pattern of a ^ b 0000000001110010 Related Information o Bitwise Inclusive OR | o Bitwise AND & o Logical OR || o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.12. Bitwise Inclusive OR | ═══ The | (bitwise inclusive OR) operator compares the values (in binary format) of each operand and yields a value whose bit pattern shows which bits in either of the operands has the value 1. If both of the bits are 0, the result of that bit is 0; otherwise, the result is 1. Both operands must have an integral type. The usual arithmetic conversions on each operand are performed. The result has the same type as the converted operands and is not an lvalue. Because the bitwise inclusive OR operator has both associative and commutative properties, the compiler may rearrange the operands in an expression that contains more than one bitwise inclusive OR operator. Note that the | character can be represented by the trigraph ??!. The following example shows the values of a, b, and the result of a | b represented as 16-bit binary numbers: bit pattern of a 0000000001011100 bit pattern of b 0000000000101110 bit pattern of a | b 0000000001111110 Note: The bitwise OR (|) should not be confused with the logical OR (||) operator. For example, 1 | 4 evaluates to 5 while 1 || 4 evaluates to 1 Related Information o Bitwise Exclusive OR ^ o Bitwise AND & o Logical OR || o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.13. Logical AND && ═══ The && (logical AND) operator indicates whether both operands have a nonzero value. If both operands have nonzero values, the result has the value 1. Otherwise, the result has the value 0. Both operands must have a scalar type. The usual arithmetic conversions on each operand are performed. The result has type int and is not an lvalue. The logical AND operator guarantees left-to-right evaluation of the operands. If the left operand evaluates to 0, the right operand is not evaluated. The following examples show how the expressions that contain the logical AND operator are evaluated: Expression Result 1 && 0 0 1 && 4 1 0 && 0 0 The following example uses the logical AND operator to avoid a divide-by-zero situation: y && (x / y) The expression x / y is not evaluated when y is 0. Note: The logical AND (&&) should not be confused with the bitwise AND (&) operator. For example: 1 && 4 evaluates to 1 while 1 & 4 evaluates to 0 Related Information o Logical OR || o Bitwise AND & o Binary Expression o Usual Arithmetic Conversions ═══ 7.6.14. Logical OR || ═══ The || (logical OR) operator indicates whether either operand has a nonzero value. If either operand has a nonzero value, the result has the value 1. Otherwise, the result has the value 0. Both operands must have a scalar type. The usual arithmetic conversions on each operand are performed. The result has type int and is not an lvalue. The logical OR operator guarantees left-to-right evaluation of the operands. If the left operand has a nonzero value, the right operand is not evaluated. The following examples show how expressions that contain the logical OR operator are evaluated: Expression Result 1 || 0 1 1 || 4 1 0 || 0 0 The following example uses the logical OR operator to conditionally increment y: ++x || ++y; The expression ++y is not evaluated when the expression ++x evaluates to a nonzero quantity. Note: The logical OR (||) should not be confused with the bitwise OR (|) operator. For example: 1 || 4 evaluates to 1 while 1 | 4 evaluates to 5 Related Information o Logical AND && o Bitwise Inclusive OR | o Binary Expression o Usual Arithmetic Conversions ═══ 7.7. Conditional Expression ? : ═══ A conditional expression is a compound expression that contains a condition (the first expression), an expression to be evaluated if the condition has a nonzero value (the second expression), and an expression to be evaluated if the condition has the value 0. The conditional expression contains one two-part operator. The ? symbol follows the condition, and the : symbol appears between the two action expressions. All expressions that occur between the ? and : are treated as one expression. The first operand must have a scalar type. The second and third operands must have arithmetic types, compatible structure type, compatible union type, or compatible pointer type. A type is compatible when it has the same type but not necessarily the same qualifiers (volatile, const, or _Packed). Also, the second and third operands may be a pointer and a NULL pointer constant, or a pointer to an object and a pointer to void. The first expression is evaluated first. If the first expression has a nonzero value, the second expression is evaluated and the third operand is not evaluated. Its result is converted to the result type. If the expression is an arithmetic type, the usual arithmetic conversions on the second expression are performed. If the first expression has a zero value, the third expression is evaluated with the usual arithmetic conversions performed on it if it has an arithmetic type. The types of the second and third operands determine the type of the result as shown in the following table. ┌─────────────────────────┬──────────────────────────┬─────────────────────────┐ │ TYPE OF ONE OPERAND │ TYPE OF OTHER OPERAND │ TYPE OF RESULT │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Arithmetic │ Arithmetic │ Arithmetic after usual │ │ │ │ arithmetic conversions │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ "struct/union" type │ Compatible │ "struct/union" type │ │ │ "struct/union" type │ with all the qualifiers │ │ │ │ on both operands │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ "void" │ "void" │ "void" │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Pointer to compatible │ Pointer to compatible │ Pointer to type with │ │ type │ type │ all the qualifiers │ │ │ │ specified for the type │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Pointer to type │ "NULL" pointer │ Pointer to type │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Pointer to object or │ Pointer to "void" │ Pointer to "void" with │ │ incomplete type │ │ all the qualifiers │ │ │ │ specified for the type │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Reference to type │ Reference to type │ Reference after usual │ │ │ │ reference conversions │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Class "T" │ Class "T" │ Class "T" │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ Class "T" │ Class "X" │ Class type for which a │ │ │ │ conversion exists. If │ │ │ │ more than one possible │ │ │ │ conversion exists, the │ │ │ │ result is ambiguous. │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ "throw" expression │ Other (type, pointer, │ Type of the expression │ │ │ reference) │ that is not a "throw" │ │ │ │ expression │ └─────────────────────────┴──────────────────────────┴─────────────────────────┘ Table 6. Type of the Conditional Expression Conditional expressions have right-to-left associativity. Examples of Conditional Expressions Related Information o Types o Declarators o Expressions and Operators o Usual Arithmetic Conversions o Operator Precedence ═══ Examples of Conditional Expressions ═══ The following expression determines which variable has the greater value, y or z, and assigns the greater value to the variable x: x = (y > z) ? y : z; The preceding expression is equivalent to the following statement: if (y > z) x = y; else x = z; The following expression calls the function printf, which receives the value of the variable c, if c evaluates to a digit. Otherwise, printf receives the character constant 'x'. printf(" c = %c\n", isdigit(c) ? c : 'x'); ═══ 7.8. Assignment Expression ═══ An assignment expression stores a value in the object designated by the left operand. The left operand in all assignment expressions must be a modifiable lvalue. The type of the expression is the type of the left operand. The value of the expression is the value of the left operand after the assignment has completed. The result of an assignment expression is not an lvalue. All assignment operators have the same precedence and have right-to-left associativity. There are two types of assignment operators: simple assignment and compound assignment. The following sections describe these operators. o Simple Assignment = o Compound Assignment Related Information o Expressions and Operators o Operator Precedence ═══ 7.8.1. Simple Assignment = ═══ The simple assignment operator stores the value of the right operand in the object designated by the left operand. Both operands must have arithmetic types, the same structure type, or the same union type. Otherwise, both operands must be pointers to the same type, or the left operand must be a pointer and the right operand must be the constant 0 or NULL. If both operands have arithmetic types, the system converts the type of the right operand to the type of the left operand before the assignment. If the right operand is a pointer to a type, the left operand can be a pointer to a const of the same type. If the right operand is a pointer to a const type, the left operand must also be a pointer to a const type. If the right operand is a pointer to a type, the left operand can be a pointer to a volatile of the same type. If the right operand is a pointer to a volatile type, the left operand must also be a pointer to a volatile type. If the left operand is a pointer to a member, the right operand must be a pointer to a member or a constant expression that evaluates to zero. The right operand is converted to the type of the left operand before assignment. If the left operand is an object of reference type, the assignment is to the object denoted by the reference. If the left operand is a pointer and the right operand is the constant 0, the result is NULL. Pointers to void can appear on either side of the simple assignment operator. A packed structure or union can be assigned to a nonpacked structure or union of the same type, and a nonpacked structure or union can be assigned to a packed structure or union of the same type. If one operand is packed and the other is not, the layout of the right operand is remapped to match the layout of the left. This remapping of structures may degrade performance. For efficiency, when you perform assignment operations with structures or unions, you should ensure that both operands are either packed or nonpacked. Note: If you assign pointers to structures or unions, the objects they point to must both be either packed or nonpacked. See Pointers for more information on assignments with pointers. You can assign values to operands with the type qualifier volatile. You cannot assign a pointer of an object with the type qualifier const to a pointer of an object without the const type qualifier such as in the following example: const int *p1; int *p2; p2 = p1; /* is not allowed */ p1 = p2; /* note that this is allowed */ Examples of Simple Assignments Note: The assignment (=) operator should not be confused with the equality comparison (==) operator. For example: if(x == 3) evaluates to 1 if x is equal to three while if(x = 3) is taken to be true because (x = 3) evaluates to a non-zero value (3). The expression also assigns the value 3 to x. Related Information o Compound Assignment o Equality == != o Pointers o volatile and const Qualifiers o Types o Usual Arithmetic Conversions ═══ Examples of Simple Assignments ═══ The following example assigns the value of number to the member employee of the structure payroll: payroll.employee = number; The following example assigns in order the value 0 to d, the value of d to c, the value of c to b, and the value of b to a: a = b = c = d = 0; ═══ 7.8.2. Compound Assignment ═══ The compound assignment operators consist of a binary operator and the simple assignment operator. They perform the operation of the binary operator on both operands and give the result of that operation to the left operand. If the left operand of the += and -= operators is a pointer, the right operand must have an integral type; otherwise, both operands must have an arithmetic type. Both operands of the *=, /=, and %= operators must have an arithmetic type. Both operands of the <<=, >>=, &=, ^=, and |= operators must have an integral type. Note that the expression a *= b + c is equivalent to a = a * (b + c), and not a = a * b + c. The following table lists the compound assignment operators and shows an expression using each operator: Operator Example += index += 2 Equivalent expression: index = index + 2 -= *(pointer++) -= 1 Equivalent expression: *pointer = *(pointer++) - 1 *= bonus *= increase Equivalent expression: bonus = bonus * increase /= time /= hours Equivalent expression: time = time / hours %= allowance %= 1000 Equivalent expression: allowance = allowance % 1000 <<= result <<= num Equivalent expression: result = result << num >>= form >>= 1 Equivalent expression: form = form >> 1 &= mask &= 2 Equivalent expression: mask = mask & 2 ^= test ^= pre_test Equivalent expression: test = test ^ pre_test |= flag |= ON Equivalent expression: flag = flag | ON Although the equivalent expression column shows the left operands (from the example column) evaluated twice, the left operand is evaluated only once. Related Information o Simple Assignment = o Binary Expression ═══ 7.9. Comma Expression , ═══ A comma expression contains two operands separated by a comma. Although the compiler evaluates both operands, the value of the right operand is the value of the expression. The left operand is evaluated, possibly producing side effects, and the value is discarded. The result of a comma expression is not an lvalue. Both operands of a comma expression can have any type. All comma expressions have left-to-right associativity. The left operand is fully evaluated before the right operand. If omega had the value 11, the following example would increment y and assign the value 3 to alpha: alpha = (y++, omega % 4); Any number of expressions separated by commas can form a single expression. The compiler evaluates the leftmost expression first. The value of the rightmost expression becomes the value of the entire expression. For example, the value of the following expression is rotate(direction): intensity++, shade * increment, rotate(direction); Restrictions You can place comma expressions within lists that contain commas (for example, argument lists and initializer lists). However, because the comma has a special meaning, you must place parentheses around comma expressions in these lists. The comma expression t = 3, t + 2 is in the following function call: f(a, (t = 3, t + 2), c); The arguments to the function f are: the value of a, the value 5, and the value of c. Related Information o Expressions and Operators o Operator Precedence ═══ 7.10. Conversions ═══ Many C and C++ operators cause conversions. A conversion changes the form of a value and its type. For example, when you add values having different data types, the compiler converts the types of the objects to the same type before adding the values. Addition of a short int value and an int value causes the compiler to convert the short int value to the int type. Conversions may occur, for example, when: o A cast operation is performed. o An operand is prepared for an arithmetic or logical operation. o An assignment is made to an lvalue that has different type from the assigned value. o A prototyped function is given an argument that has a different type from the parameter. o The type of the expression specified on a function's return statement has a different type from the defined return type for the function. Although the C and C++ languages contain some guidelines for conversions, many conversions have implementation-specific aspects. These implementation specific aspects occur because: o The sizes of the data types vary. o The manner of handling signed data varies. o The data formats vary. The following sections describe conversions: o Usual Arithmetic Conversions o Type Conversions Related Information o Expressions and Operators o Types o Cast Expressions o Functions ═══ 7.10.1. Usual Arithmetic Conversions ═══ Most C and C++ operators perform type conversions to bring the operands of an expression to a common type or to extend short values to the integer size used in machine operations. The conversions performed by the operators depend on the specific operator and the type of the operand or operands. However, many operators perform similar conversions on operands of integer and floating-point types. These conversions are known as standard arithmetic conversions because they apply to the types of values ordinarily used in arithmetic. Integer promotions are performed when you use a char, short int, int, bit field, or an enumeration type wherever an int or unsigned int is expected. If an int can hold the value, the value is converted to an int; otherwise, it is converted to an unsigned int. All other arithmetic types are unchanged by integer promotions. Type Conversions outlines the path of each type of conversion. Arithmetic conversion proceeds in the following order: 1. If one operand has long double type, the other operand is converted to long double type. 2. If one operand has double type, the other operand is converted to double. 3. If one operand has float type, the other operand is converted to float. 4. If one operand has unsigned long int type, the other operand is converted to unsigned long int. 5. If one operand has unsigned int type and the other operand has long int type and the value of the unsigned int can be represented in a long int, the operand with unsigned int type is converted to long int. 6. If one operand has unsigned int type and the other operand has long int type and the value of the unsigned int cannot be represented in a long int, both operands are converted to unsigned long int. 7. If one operand has long int type, the other operand is converted to long int. 8. If one operand has unsigned int type, the other operand is converted to unsigned int. 9. Both operands have int type, and the result is type int. Related Information o Type Conversions o Types o Expressions and Operators ═══ 7.10.2. Type Conversions ═══ Type conversions are the assignment of a value to a variable of a different data type, when: o A value is explicitly cast to another type. o An operator converts the type of its operand or operands before performing an operation. o A value is passed as an argument to a function. The following sections outline the rules governing each kind of conversion. Assignment Conversions In assignment operations, the type of the value being assigned is converted to the type of the variable receiving the assignment. C and C++ allow conversions by assignment between integer and floating-point types, even when the conversion entails loss of information. On IBM C compilers, int types are handled in the same manner as long types. The methods of carrying out the conversions depend upon the type: o Conversion from Signed Integer Types o Conversion from Unsigned Integer Types o Conversion from Floating-Point Types o Conversion to and from Pointer Types o Conversion from Other Types Related Information o Types o Expressions and Operators o Cast Expressions o Usual Arithmetic Conversions ═══ 7.10.2.1. Conversion from Signed Integer Types ═══ C and C++ convert a signed integer to a shorter signed integer by truncating the high-order bits and converting it to a longer signed integer by sign-extension. Conversion of signed integers to floating-point values takes place without loss of information, except that some precision can be lost when a long value is converted to a float. To convert a signed integer to an unsigned integer, you must convert the signed integer to the size of the unsigned integer. The result is interpreted as an unsigned value. The following chart summarizes conversions from signed integer types: ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "signed │ "short" │ Sign-extend. │ │ char" │ │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Sign-extend. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Sign-extend. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve pattern; high-order bit loses func- │ │ │ char" │ tion as sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Sign-extend to "short"; convert "short" to │ │ │ short" │ "unsigned short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Sign-extend to "long"; convert "long" to │ │ │ long" │ "unsigned long". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Sign-extend to "long"; convert "long" to │ │ │ │ "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Sign-extend to "long"; convert "long" to │ │ │ │ "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Sign-extend to "long"; convert "long" to "long │ │ │ double" │ double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "short" │ "signed │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Sign-extend. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Sign-extend. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve bit pattern; high-order bit loses │ │ │ short" │ function as sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Sign-extend to "long"; convert "long" to │ │ │ long" │ "unsigned long". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Sign-extend to "long"; convert "long" to │ │ │ │ "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Sign-extend to "long"; convert "long" to │ │ │ │ "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Sign-extend to "long"; convert "long" to "long │ │ │ double" │ double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "int" │ "signed │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Preserve low-order bytes. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order bytes. │ │ │ short" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve bit pattern; high-order bit loses │ │ │ long" │ function as sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Represent as a "float"; if the "long" cannot │ │ │ │ be represented exactly, some loss of precision │ │ │ │ occurs. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Represent as a "double"; if the "long" cannot │ │ │ │ be represented exactly, some loss of precision │ │ │ │ occurs. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Represent as a "long double"; if the "long" │ │ │ double" │ cannot be represented exactly, some loss of │ │ │ │ precision occurs. │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "long" │ "signed │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Preserve low-order bytes. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order bytes. │ │ │ short" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve bit pattern; high-order bit loses │ │ │ long" │ function as sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Represent as a "float"; if the "long" cannot │ │ │ │ be represented exactly, some loss of precision │ │ │ │ occurs. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Represent as a "double"; if the "long" cannot │ │ │ │ be represented exactly, some loss of precision │ │ │ │ occurs. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Represent as a "long double"; if the "long" │ │ │ double" │ cannot be represented exactly, some loss of │ │ │ │ precision occurs. │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ Related Information o Conversion from Unsigned Integer Types o Conversion from Floating-Point Types o Conversion to and from Pointer Types o Conversion from Other Types o Integers o Types o Type Conversions o Usual Arithmetic Conversions ═══ 7.10.2.2. Conversion from Unsigned Integer Types ═══ An unsigned integer is converted to a shorter unsigned or signed integer by truncating the high-order bits. An unsigned integer is converted to a longer unsigned or signed integer by setting the high-order bits to 0. Unsigned values are converted to floating-point values by first converting to a signed integer of the same size, and then converting that signed value to a floating-point value. When an unsigned integer is converted to a signed integer of the same size, no change in the bit pattern occurs. However, the value changes if the sign bit is set. The following chart summarizes conversions from unsigned integer types: ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "unsigned │ "signed │ Preserve bit pattern; high-order bit becomes │ │ char" │ char" │ sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Zero-extend; preserve the bit pattern. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Zero-extend; preserve the bit pattern. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Zero-extend; preserve the bit pattern. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Zero-extend; preserve the bit pattern. │ │ │ short" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Zero-extend; preserve the bit pattern. │ │ │ int" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Zero-extend; preserve the bit pattern. │ │ │ long" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Convert to "long"; convert "long" to "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Convert to "long"; convert "long" to "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Convert to "long"; convert "long" to "long │ │ │ double" │ double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "unsigned │ "signed │ Preserve low-order byte. │ │ short" │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Preserve bit pattern; high-order bit becomes │ │ │ │ sign bit. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Zero-extend; preserve the bit pattern. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Zero-extend; preserve the bit pattern. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Zero-extend. │ │ │ int" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Zero-extend. │ │ │ long" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Convert to "long"; convert "long" to "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Convert to "long"; convert "long" to "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Convert to "long"; convert "long" to "long │ │ │ double" │ double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "unsigned │ "signed │ Preserve low-order byte. │ │ int" │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Preserve low-order bytes. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Preserve bit pattern; high-order bit becomes │ │ │ │ sign. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Preserve bit pattern; high-order bit becomes │ │ │ │ sign. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order bytes. │ │ │ short" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Convert "int" to "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Convert "int" to "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Convert "int" to "long double". │ │ │ double" │ │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "unsigned │ "signed │ Preserve low-order byte. │ │ long" │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Preserve low-order bytes. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Preserve bit pattern; high-order bit becomes │ │ │ │ sign. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Preserve bit pattern; high-order bit becomes │ │ │ │ sign. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order byte. │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Preserve low-order bytes. │ │ │ short" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Convert "long" to "float". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Convert "long" to "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Convert "long" to "long double". │ │ │ double" │ │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ Related Information o Conversion from Signed Integer Types o Conversion from Floating-Point Types o Conversion to and from Pointer Types o Conversion from Other Types o Integers o Types o Type Conversions o Usual Arithmetic Conversions ═══ 7.10.2.3. Conversion from Floating-Point Types ═══ A float value converted to a double undergoes no change in value. A double converted to a float is represented exactly, if possible. If C cannot exactly represent the double value as a float, the number loses precision. If the value is too large to fit into a float, the number is undefined. A floating-point value is converted to an integer value by converting to an unsigned long. The decimal fraction portion of the floating-point value is discarded in the conversion. If the result is still too large to fit, the result of the conversion is undefined. The following chart summarizes conversions from floating-point types: ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "float" │ "signed │ Convert to "long"; convert "long" to "signed │ │ │ char" │ char". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Convert to "long"; convert "long" to "short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "int", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "long", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Convert to "unsigned long"; convert "unsigned │ │ │ short" │ long" to "unsigned short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ int" │ large to be represented as an "unsigned int", │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ long" │ large to be represented as an "unsigned long", │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Represent as a "double". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "double" │ "signed │ Convert to "float"; convert "float" to "char". │ │ │ char" │ │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Convert to "float"; convert "float" to │ │ │ │ "short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "long", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "long", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Convert to "unsigned long"; convert "unsigned │ │ │ short" │ long" to "unsigned short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ int" │ large to be represented as an "unsigned int", │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ long" │ large to be represented as a "long", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Represent as a float; if the "double" value │ │ │ │ cannot be represented exactly as a "float", │ │ │ │ loss of precision occurs; if the value is too │ │ │ │ large to be represented in a "float", the │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long │ Represent as a "long double". │ │ │ double" │ │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ ┌──────────────┬──────────────┬────────────────────────────────────────────────┐ │ FROM │ TO │ METHOD │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ "long │ "signed │ Convert to "double"; convert "double" to │ │ double" │ char" │ "float"; convert "float" to "char". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "short" │ Convert to "double"; convert "double" to │ │ │ │ "float"; convert "float" to "short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "int" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "int", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "long" │ Truncate at decimal point; if result is too │ │ │ │ large to be represented as a "long", result is │ │ │ │ undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Convert to "double"; convert "double" to │ │ │ short" │ "unsigned long"; convert "unsigned long" to │ │ │ │ "unsigned short". │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ int" │ large to be represented as an "unsigned int", │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "unsigned │ Truncate at decimal point; if result is too │ │ │ long" │ large to be represented as an "unsigned long", │ │ │ │ result is undefined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "float" │ Convert to "double"; represent as a "float"; │ │ │ │ if the "long double" value cannot be repres- │ │ │ │ ented exactly as a "float", loss of precision │ │ │ │ occurs; if the value is too large to be │ │ │ │ represented in a "float", the result is unde- │ │ │ │ fined. │ ├──────────────┼──────────────┼────────────────────────────────────────────────┤ │ │ "double" │ Represent as a "double"; If the result is too │ │ │ │ large to be represented as a "double", result │ │ │ │ is undefined. │ └──────────────┴──────────────┴────────────────────────────────────────────────┘ Related Information o Conversion from Signed Integer Types o Conversion from Unsigned Integer Types o Conversion to and from Pointer Types o Conversion from Other Types o Floating-Point Variables o Types o Type Conversions o Usual Arithmetic Conversions ═══ 7.10.2.4. Conversion to and from Pointer Types ═══ You can convert a pointer to one type of value to a pointer to a different type. You can convert a pointer value to an integral value. The path of the conversion depends on the size of the pointer and the size of the integral type. The conversion of an integer value to an address offset (in an expression with an integral type operand and a pointer type operand) is system dependent. A pointer to a constant or a volatile object should never be assigned to a nonconstant or nonvolatile object. A pointer to void can be converted to or from a pointer to any incomplete or object type. Related Information o Conversion from Signed Integer Types o Conversion from Unsigned Integer Types o Conversion from Floating-Point Types o Conversion from Other Types o Pointers o volatile and const Qualifiers o Types o Type Conversions o Usual Arithmetic Conversions ═══ 7.10.2.5. Conversion from Other Types ═══ When you define a value using the enum type specifier, the value is treated as an int. Conversions to and from an enum value proceed as for the int type. When a packed structure or union is assigned to a nonpacked structure or union of the same type or an nonpacked structure is assigned to, a packed structure or union of the same type, the layout of the right operand is remapped to match the layout of the left. No other conversions between structure or union types are allowed. The void type has no value, by definition. Therefore, it cannot be converted to any other type, nor can any value be converted to void by assignment. However, a value can be explicitly cast to void. Related Information o Conversion from Signed Integer Types o Conversion from Unsigned Integer Types o Conversion from Floating-Point Types o Conversion to and from Pointer Types o Enumerations o Integers o Structures o Unions o _Packed Qualifier o void Type o Cast Expressions o Type Conversions o Usual Arithmetic Conversions ═══ 8. Language Statements ═══ This section describes the following C and C++ language statements: o Labels o Block o break o continue o do o Expression o for o goto o if o Null Statement o return o switch o while ═══ 8.1. Labels ═══ A label is an identifier that allows your program to transfer control to other statements within the same function. A label is the only type of identifier that has function scope. (See Scope in C.) Control is transferred to the statement following the label by means of the goto or switch statements. A label has the form: >>──identifier──:──statement──>< For example, the following are labels: comment_complete: ; /* Example of null statement label */ test_for_null: if (NULL == ptr) /* Example of statement label */ The case and default labels have a specific use and are described under switch. Related Information o goto o switch ═══ 8.2. Block ═══ A block statement enables you to group any number of data definitions, declarations, and statements into one statement. When you enclose definitions, declarations, and statements within a single set of braces, everything within the braces is treated as a single statement. You can place a block wherever a statement is allowed. Syntax of a Block Statement All definitions and declarations occur at the beginning of a block before statements. Statements must follow the definitions and declarations. A block is considered a single statement. If you redefine a data object inside a nested block, the inner object hides the outer object while the inner block is executed. Defining several variables that have the same identifier can make a program difficult to understand and maintain. Therefore, you should limit such redefinitions of identifiers within nested blocks. If a data object is usable within a block, all nested blocks can use that data object (unless that data object identifier is redefined). Initialization of an auto or register variable occurs each time the block is executed from the beginning. If you transfer control from one block to the middle of another block, initializations are not always performed. You cannot initialize an extern variable within a block. A static local object is initialized only once, when control passes through its declaration for the first time. A static variables initialized with an expression other than a constant expression is initialized to 0 before its block is first entered. Note: Unlike ANSI C, in C++ it is an error to jump over a declaration or definition containing an initializer. When control exits from a block, all objects with destructors that are defined in the block are destroyed. The destructor for a static local object is called only if the object was constructed. The destructor must be called before or as part of the atexit function. Local variables declared in a block are also destroyed on exit. Automatic variables defined in a loop are destroyed at each iteration. Examples of Block Statements Related Information o Block Scope Data Declarations o Function Body o auto Storage Class Specifier o register Storage Class Specifier o static Storage Class Specifier o extern Storage Class Specifier o atexit - Record Program Termination Function ═══ Syntax of a Block Statement ═══ The block statement has the form: ┌─────────────────────────────┐ ┌───────────────┐  │  │ ──{──┬───────────────────────────┬┴───┬─────────────┬┴─}── │ │ │ │ ├──type_definition──────────┤ └──statement──┘ │ │ ├──extern_declaration───────┤ │ │ └──internal_data_definition─┘ ═══ Examples of Block Statements ═══ /************************************************************************ * The following example shows how the values of data objects change in nested blocks: * ************************************************************************/ 1 #include 2 3 int main(void) 4 { 5 int x = 1; /* Initialize x to 1 */ 6 int y = 3; 7 8 if (y > 0) 9 { 10 int x = 2; /* Initialize x to 2 */ 11 printf("second x = %4d\n", x); 12 } 13 printf("first x = %4d\n", x); 14 } /************************************************************************ * The preceding example produces the following output: second x = 2 first x = 1 Two variables named x are defined in main. The definition of x on line 5 retains storage throughout the execution of main. However, because the definition of x on line 10 occurs within a nested block, line 11 recognizes x as the variable defined on line 10. Line 13 is not part of the nested block. Thus, line 13 recognizes x as the variable defined on line 5. * ************************************************************************/ ═══ 8.3. break ═══ A break statement enables you to terminate and exit from a loop or switch statement from any point within the loop or switch other than the logical end. A break statement has the form: >>──break──;──────────────────────────────────────────────────────────────────>< In a looping statement (do, for, or while), the break statement ends the loop and moves control to the next statement outside the loop. Within nested statements, the break statement ends only the smallest enclosing do, for, switch, or while statement. In a switch body, the break statement ends the execution of the switch body and gives control to the next statement outside the switch body. You can place a break statement only in the body of a looping statement (do, for or while) or in the body of a switch statement. Examples of break Statements Related Information o do o for o switch o while ═══ Examples of break Statements ═══ /************************************************************************ * The following example shows a break statement in the action part of a for statement. If the ith element of the array string is equal to '\0', the break statement causes the for statement to end. for (i = 0; i < 5; i++) { if (string[i] == '\0') break; length++; } The preceding for statement is equivalent to the following for statement, if string does not contain any embedded null characters: for (i = 0; i < 5; i++) { if (string[i] != '\0') length++; } The following example shows a break statement in a nested looping statement. The outer loop sequences an array of pointers to strings. The inner loop examines each character of the string. When the break statement is executed, the inner loop ends and control returns to the outer loop. * ************************************************************************/ /* ** This program counts the characters in the strings that are ** part of an array of pointers to characters. The count stops ** when one of the digits 0 through 9 is encountered ** and resumes at the beginning of the next string. */ #include #define SIZE 3 int main(void) { static char *strings[SIZE] = { "ab", "c5d", "e5" }; int i; int letter_count = 0; char *pointer; for (i = 0; i < SIZE; i++) /* for each string */ /* for each character */ for (pointer = strings[i]; *pointer != '\0'; ++pointer) { /* if a number */ if (*pointer >= '0' && *pointer <= '9') break; letter_count++; } printf("letter count = %d\n", letter_count); } /************************************************************************ * The preceding program produces the following output: letter count = 4 The following example is a switch statement that contains several break statements. Each break statement indicates the end of a specific clause and ends the execution of the switch statement. enum {morning, afternoon, evening} timeofday; switch (timeofday) { case (morning): printf("Good Morning\n"); break; case (evening): printf("Good Evening\n"); break; default: printf("Good Day, eh\n"); break; } * ************************************************************************/ ═══ 8.4. continue ═══ A continue statement enables you to terminate the current iteration of a loop. Program control is passed from the location in the body of the loop in which the continue statement is found to the end of the loop body. A continue statement has the form: ──continue──;── The continue statement ends the execution of the action part of a do, for, or while statement and moves control to the condition part of the statement. If the looping statement is a for statement, control moves to the third expression in the condition part of the statement, and then to the second expression (the test) in the condition part of the statement. Within nested statements, the continue statement ends only the current iteration of the do, for, or while statement immediately enclosing it. You can place a continue statement only within the body of a looping statement (do, for or while). Examples of continue Statements Related Information o do o for o while ═══ Examples of continue Statements ═══ /************************************************************************ * The following example shows a continue statement in a for statement. The continue statement causes the system to skip over those elements of the array rates that have values less than or equal to 1. * ************************************************************************/ #include #define SIZE 5 int main(void) { int i; static float rates[SIZE] = { 1.45, 0.05, 1.88, 2.00, 0.75 }; printf("Rates over 1.00\n"); for (i = 0; i < SIZE; i++) { if (rates[i] <= 1.00) /* skip rates <= 1.00 */ continue; printf("rate = %.2f\n", rates[i]); } } /************************************************************************ * The preceding program produces the following output: Rates over 1.00 rate = 1.45 rate = 1.88 rate = 2.00 The following example shows a continue statement in a nested loop. When the inner loop encounters a number in the array strings, that iteration of the loop is terminated. Execution continues with the third expression of the inner loop (See for). The inner loop is terminated when the '\0' escape sequence is encountered. * ************************************************************************/ /************************************************************************ ** This program counts the characters in strings that are part ** ** of an array of pointers to characters. The count excludes ** ** the digits 0 through 9. ** *************************************************************************/ #include #define SIZE 3 int main(void) { static char *strings[SIZE] = { "ab", "c5d", "e5" }; int i; int letter_count = 0; char *pointer; for (i = 0; i < SIZE; i++) /* for each string */ /* for each each character */ for (pointer = strings[i]; *pointer != '\0'; ++pointer) { /* if a number */ if (*pointer >= '0' && *pointer <= '9') continue; letter_count++; } printf("letter count = %d\n", letter_count); } /************************************************************************ * The preceding program produces the following output: letter count = 5 * ************************************************************************/ ═══ 8.5. do ═══ A do statement repeatedly executes a statement until the test expression evaluates to 0. Because of the order of execution, the statement is executed at least once. A do statement has the form: ──do──statement──while──(──expression──)──;── The body of the loop is executed before the while clause (the controlling expression) is evaluated. Further execution of the do statement depends on the value of the while clause. If the while clause does not evaluate to 0, the statement is executed again. Otherwise, execution of the statement ends. The controlling expression must be of scalar type. A break, return, or goto statement can cause the execution of a do statement to end, even when the while clause does not evaluate to 0. Example of a do Statement Related Information o break o continue o for o goto o return o while ═══ Example of a do Statement ═══ /************************************************************************ * The following statement prompts the user to enter a 1. If the user enters a 1, the statement ends execution. Otherwise, the statement displays another prompt. * ************************************************************************/ #include int main (void) { int reply1; do { printf("Enter a 1\n"); scanf("%d", &reply1); } while (reply1 != 1); } ═══ 8.6. Expression ═══ An expression statement contains an expression. Expressions are described in Expressions and Operators. An expression statement has the form: ──┬──────────────┬──;── │ │ └──expression──┘ An expression statement evaluates the given expression. An expression statement is used to assign the value of the expression to a variable or to call a function. The following are examples of expressions: printf("Account Number: \n"); /* A call to printf */ marks = dollars * exch_rate; /* An assignment to marks */ (difference < 0) ? ++losses : ++gain; /* A conditional increment */ switches = flags | BIT_MASK; /* An assignment to switches */ Related Information o Expressions and Operators o Resolving Ambiguous Statements ═══ 8.7. for ═══ A for statement enables you to do the following: o Evaluate an expression prior to the first iteration of the statement ("initialization") o Specify an expression to determine whether or not the statement should be executed ("controlling part") o Evaluate an expression after each iteration of the statement A for statement has the form: ──for──(──┬───────────────┬──;──┬───────────────┬──;── │ │ │ │ └──expression1──┘ └──expression2──┘ ──┬───────────────┬──)──statement── │ │ └──expression3──┘ The compiler evaluates expression1 only once; before the statement is executed for the first time. You can use this expression to initialize a variable. If you do not want to evaluate an expression prior to the first iteration of the statement, you can omit this expression. In C++ programs, you can also use expression1 to declare a variable as well as initialize it. If you declare a variable in this expression, the variable has the same scope as the for statement and is not local to the for statement. The compiler evaluates expression2 before each execution of the statement. expression2 must evaluate to a scalar type. If this expression evaluates to 0, the for statement is terminated and control moves to the statement following the for statement. Otherwise, the statement is executed. If you omit expression2, it will be as if the expression had been replaced by a nonzero constant and the for statement will not be terminated by failure of this condition. The compiler evaluates expression3 after each execution of the statement. You can use this expression to increase, decrease, or reinitialize a variable. If you do not want to evaluate an expression after each iteration of the statement, you can omit this expression. A break, return, or goto statement can cause the execution of a for statement to end, even when the second expression does not evaluate to 0. If you omit expression2, you must use a break, return, or goto statement to stop the execution of the for statement. Examples of for Statements Related Information o break o continue o do o return o goto o while o Expressions and Operators ═══ Examples of for Statements ═══ The following for statement prints the value of count 20 times. The for statement initially sets the value of count to 1. After each execution of the statement, count is incremented. for (count = 1; count <= 20; count++) printf("count = %d\n", count); For comparison purposes, the preceding example can be written using the following sequence of statements to accomplish the same task. Note the use of the while statement instead of the for statement. count = 1; while (count <= 20) { printf("count = %d\n", count); count++; } The following for statement does not contain an initialization expression: for (; index > 10; --index) { list[index] = var1 + var2; printf("list[%d] = %d\n", index, list[index]); } The following for statement will continue executing until scanf receives the letter e: for (;;) { scanf("%c", &letter); if (letter == '\n') continue; if (letter == 'e') break; printf("You entered the letter %c\n", letter); } The following for statement contains multiple initializations and increments. The comma operator makes this construction possible. The first comma in the for expression is a punctuator for a declaration; that is, it declares and initializes two integers, i and j. The second comma, a comma operator, allows both i and j to be incremented at each step through the loop. for (int i = 0, j = 50; i < 10; ++i, j += 50) { cout << "i = " << i << "and j = " << j << endl; } The following example shows a nested for statement. The outer statement is executed as long as the value of row is less than 5. Each time the outer for statement is executed, the inner for statement sets the initial value of column to zero and the statement of the inner for statement is executed 3 times. The inner statement is executed as long as the value of column is less than 3. This example prints the values of an array having the dimensions [5][3]: for (row = 0; row < 5; row++) for (column = 0; column < 3; column++) printf("%d\n", table[row][column]); ═══ 8.8. goto ═══ A goto statement causes your program to unconditionally transfer control to the statement associated with the label specified on the goto statement. A goto statement has the form: ──goto──identifier──;── The goto statement transfers control to the statement indicated by the identifier. Use the goto statement sparingly. Because the goto statement can interfere with the normal top-to-bottom sequence of execution, it makes a program more difficult to read and maintain. Often, a break statement, a continue statement, or a function call can eliminate the need for a goto statement. If you use a goto statement to transfer control to a statement inside of a loop or block, initializations of automatic storage for the loop do not take place and the result is undefined. The label must appear in the same function as the goto. If an active block is exited using a goto statement, any local variables are destroyed when control is transferred from that block. Example of a goto Statement Related Information o Labels o break o continue o Functions ═══ Example of a goto Statement ═══ The following example shows a goto statement that is used to jump out of a nested loop. This function could be written without using a goto statement. void display(int matrix[3][3]) { int i, j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if ( (matrix[i][j] < 1) || (matrix[i][j] > 6) ) goto out_of_bounds; printf("matrix[%d][%d] = %d\n", i, j, matrix[i][j]); } return; out_of_bounds: printf("number must be 1 through 6\n"); } ═══ 8.9. if ═══ An if statement allows you to conditionally execute a statement when the specified test expression evaluates to a nonzero value. The expression must have a scalar type. You may optionally specify an else clause on the if statement. If the test expression evaluates to 0 and an else clause exists, the statement associated with the else clause is executed. An if statement has the form: ──if──(──expression──)──statement──┬───────────────────┬── │ │ └──else──statement──┘ When if statements are nested and else clauses are present, a given else is associated with the closest preceding if statement within the same block. Examples of if Statements Related Information o Conditional Compilation o switch ═══ Examples of if Statements ═══ The following example causes grade to receive the value A if the value of score is greater than or equal to 90. if (score >= 90) grade = 'A'; The following example displays number is positive if the value of number is greater than or equal to 0. Otherwise, the example displays number is negative. if (number >= 0) printf("number is positive\n"); else printf("number is negative\n"); The following example shows a nested if statement: if (paygrade == 7) if (level >= 0 && level <= 8) salary *= 1.05; else salary *= 1.04; else salary *= 1.06; cout << "salary is " << salary << endl; The following example shows an if statement that does not have an else clause. Because an else clause always associates with the closest if statement, braces may be necessary to force a particular else clause to associate with the correct if statement. In this example, omitting the braces would cause the else clause to associate with the nested if statement. if (gallons > 0) { if (miles > gallons) mpg = miles/gallons; } else mpg = 0; The following example shows an if statement nested within an else clause. This example tests multiple conditions. The tests are made in order of their appearance. If one test evaluates to a nonzero value, a statement executes and the entire if statement ends. if (value > 0) ++increase; else if (value == 0) ++break_even; else ++decrease; ═══ 8.10. Null Statement ═══ The null statement performs no operation and has the form: ──;── You can use a null statement in a looping statement to show a nonexistent action or in a labeled statement to hold the label. The following example initializes the elements of the array price. Because the initializations occur within the for expressions, a statement is only needed to finish the for syntax; no operations are required. for (i = 0; i < 3; price[i++] = 0) ; Related Information o # (Null Directive) o Labels ═══ 8.11. return ═══ A return statement terminates the execution of the current function and returns control to the caller of the function. A return statement has the form: ──return──┬──────────────┬──;── │ │ └──expression──┘ A return statement ends the execution of the current function. A return statement is optional. If the system reaches the end of a function without encountering a return statement, control is passed to the caller as if a return statement without an expression were encountered. A function can contain multiple return statements. If an expression is present on a return statement, the value of the expression is returned to the caller. If the data type of the expression is different from the data type of the function, conversion of the return value takes place as if the value of the expression were assigned to an object with the same data type as the function. If an expression is not present on a return statement, the value of the return statement is not defined. If an expression is not given on a return statement and the calling function is expecting a value to be returned, the resulting behavior is undefined. You cannot use a return statement with an expression when the function is declared as returning type void. If a function returns a class object with constructors, a temporary class object may be constructed. The temporary object is not in the scope of the function returning the temporary object but is local to the caller of the function. When a function returns, all temporary local variables are destroyed. If local class objects with destructors exist, destructors are called. For more details, see Temporary Objects. You can use the /Wret compiler option to generate diagnostic messages about the use of return statements in your functions. Examples of return Statements Related Information o Functions o Using the /Wgrp Diagnostic Options o Temporary Objects o Expression ═══ Examples of return Statements ═══ The following are examples of return statements: return; /* Returns no value */ return result; /* Returns the value of result */ return 1; /* Returns the value 1 */ return (x * x); /* Returns the value of x * x */ The following function searches through an array of integers to determine if a match exists for the variable number. If a match exists, the function match returns the value of i. If a match does not exist, the function match returns the value -1 (negative one). int match(int number, int array[ ], int n) { int i; for (i = 0; i < n; i++) if (number == array[i]) return (i); return(-1); } ═══ 8.12. switch ═══ A switch statement enables you to transfer control to different statements within the switch body depending on the value of the switch expression. The switch expression must have an integral type. Within the body of the switch statement, there are case labels that consist of a label, a case expression (that evaluates to an integral value), and statements, plus an optional default label. If the value of the switch expression equals the value of one of the case expressions, the statements following that case expression are executed. Otherwise, the default label statements, if any, are executed. A switch statement has the form: ──switch──(──expression──)──switch_body── A switch body can have a simple or complex form. The simple form contains any number of case labels mixed with an optional default label. The simple form ends with a single statement. Because only the final case or default label can be followed by a statement, the simple form of the switch body is rarely used in C language programs. An if statement usually can replace a switch statement that has a simple switch body. The complex form of a switch body is enclosed in braces and can contain definitions, declarations, case clauses, and a default clause. Each case and default clause can contain statements. Syntax of a switch Body A case clause contains a case label followed by any number of statements. A case label contains the word case followed by a constant expression and a colon. Anywhere you can place one case label, you can place multiple case labels. A default clause contains a default label followed by one or more statements. You can place a case label on either side of the default label. A default_label contains the word default and a colon. A switch statement can have only one default label. The switch statement passes control to the statement following one of the labels or to the statement following the switch body. The value of the expression that precedes the switch body determines which statement receives control. This expression is called the switch expression. The value of the switch expression is compared with the value of the expression in each case label. If a matching value is found, control is passed to the statement following the case label that contains the matching value. If the system does not find a matching value and a default label appears anywhere in the switch body, control passes to the default labelled statement. Otherwise, no part of the switch body is executed. If control passes to a statement in the switch body, control does not pass from the switch body until a break statement is encountered or the last statement in the switch body is executed. An integral promotion is performed on the controlling expression, if necessary, and all expressions in the case statements are converted to the same type as the controlling expression. Restrictions The switch expression and the case expressions must have an integral type. The value of each case expression must represent a different value and must be a constant expression. Only one default label can occur in each switch statement. You can place data definitions at the beginning of the switch body. However, the compiler does not initialize auto and register variables at the beginning of a switch body. C++ Consideration: You can have declarations in the body of the switch statement. In C++, you cannot transfer control over a declaration containing an initializer unless the declaration is located in an inner block that is completely bypassed by the transfer of control. All declarations within the body of a switch statement that contain initializers must be contained in an inner block. Examples of switch Statements Related Information o break o if o Labels o Expression o Types o Storage Class Specifiers ═══ Syntax of a switch Body ═══ The simple form of a switch body is shown below: ──┬──case_label──statement────────────────────────────────────────┬── │ │ └─┬──────────────┬──default_label──┬──────────────┬──statement──┘ │ │ │ │ └──case_label──┘ └──case_label──┘ The complex form of a switch body is shown below: ┌──────────────────────────────┐ ┌─────────────────┐  │  │ ──{──┬────────────────────────────┬┴──┬───────────────┬┴─ │ │ │ │ ├──type_definition───────────┤ └──case_clause──┘ │ │ ├──extern_declaration────────┤ │ │ └──internal_data_definition──┘ ┌─────────────────┐  │ ──┬──────────────────┬──┬───────────────┬┴─}── │ │ │ │ └──default_clause──┘ └──case_clause──┘ A case clause has the form: ┌───────────┐  │ ──case_label───statement─┴── A case label has the form: ┌──────────────────────────────┐  │ ───case──constant_expression──:─┴─ A default clause has the form: ┌───────────┐  │ ──┬──────────────┬──default_label──┬──────────────┬──statement─┴─ │ │ │ │ └──case_label──┘ └──case_label──┘ A default label has the form: ──default──:── ═══ Examples of switch Statements ═══ The following switch statement contains several case clauses and one default clause. Each clause contains a function call and a break statement. The break statements prevent control from passing down through each statement in the switch body. If the switch expression evaluated to '/', the switch statement would call the function divide. Control would then pass to the statement following the switch body. char key; cout << "Enter an arithmetic operator\n"); cin >> key; switch (key) { case '+': add(); break; case '-': subtract(); break; case '*': multiply(); break; case '/': divide(); break; default: cout << "The key you pressed is not valid\n"; break; } If the switch expression matches a case expression, the statements following the case expression are executed until a break statement is encountered or the end of the switch body is reached. In the following example, break statements are not present. If the value of text[i] is equal to 'A', all three counters are incremented. If the value of text[i] is equal to 'a', lettera and total are increased. Only total is increased if text[i] is not equal to 'A' or 'a'. char text[100]; int capa, lettera, total; for (i=0; i Example fo a while Statement ═══ /************************************************************************ * In the following program, item[index] triples each time the value of the expression ++index is less than MAX_INDEX. When ++index evaluates to MAX_INDEX, the while statement ends. * ************************************************************************/ #define MAX_INDEX (sizeof(item) / sizeof(item[0])) #include int main(void) { static int item[ ] = { 12, 55, 62, 85, 102 }; int index = 0; while (index < MAX_INDEX) { item[index] *= 3; printf("item[%d] = %d\n", index, item[index]); ++index; } } ═══ 9. Preprocessor Directives ═══ This section describes the preprocessor directives. Preprocessing is a step in the compilation process that enables you to: o Replace tokens in the current file with specified replacement tokens. A token is a series of characters delimited by white space. The only white space allowed on a preprocessor directive is the space, horizontal tab, and comments. o Imbed files within the current file o Conditionally compile sections of the current file o Change the line number of the next line of source and change the file name of the current file o Generate diagnostic messages. The preprocessor recognizes the following directives: o #define o #undef o #error o #include o #if, #elif o #ifdef o #ifndef o #else o #endif o #line o #pragma This section also describes: o The # operator o Macro concatenation with the ## operator o The null directive (#) o Predefined macros. The format of a preprocessor directive is described in Preprocessor Directive Format. Related Information o Preprocessor Options ═══ 9.1. Preprocessor Directive Format ═══ Preprocessor directives begin with the # token followed by a preprocessor keyword. The # token must appear as the first character that is not white space on a line. A preprocessor directive ends at the new-line character unless the last character of the line is the \ (backslash) character. If the \ character appears as the last character in the preprocessor line, the preprocessor interprets the \ and the new-line character as a continuation marker and interprets the following line as a continuation of the current preprocessor line. Preprocessor directives can appear anywhere in a program. Related Information o Preprocessor Directives ═══ 9.2. #define ═══ A preprocessor define directive directs the preprocessor to replace all subsequent occurrences of a macro with specified replacement tokens. A preprocessor #define directive has the form: ┌─────────────┐  │ >>───#───define──identifier──┬────────────────────────┬───┬───────────┬┴──>< │ ┌─,────────────┐ │ ├─identifer─┤ │  │ │ │ │ └─(───┬────────────┬┴──)─┘ └─character─┘ └─identifier─┘ The #define directive can contain an object-like definition or a function-like definition A macro invocation must have the same number of arguments as the corresponding macro definition has parameters. In the macro invocation argument list, commas that appear as character constants, in string constants or surrounded by parentheses, do not separate arguments. The scope of a macro definition begins at the definition and does not end until a corresponding #undef directive is encountered. If there is no corresponding #undef directive, the scope of the macro definition lasts until the end of the compilation is reached. A recursive macro is not fully expanded. For example, the definition #define x(a,b) x(a+1,b+1) + 4 would expand x(20,10) to x(20+1,10+1) + 4 rather than trying to expand the macro x over and over within itself. A definition is not required to specify replacement tokens. The following definition removes all instances of the token static from subsequent lines in the current file: #define static You can change the definition of a defined identifier or macro with a second preprocessor #define directive only if the second preprocessor #define directive is preceded by a preprocessor #undef directive. See #undef. The #undef directive nullifies the first definition so that the same identifier can be used in a redefinition. You can also use the /D compiler option to define macros on the command line. Macros defined on the command line override macros defined in the source code. Within the text of the program, the preprocessor does not scan character constants or string constants for macro invocations. Examples of #define Directives Related Information o Object-Like Macro Definition o Function-Like Macro Definition o #undef o /D option o # Operator o ## Operator ═══ 9.2.1. Object-Like Macro Definition ═══ An object-like macro definition replaces a single identifier with the specified replacement tokens. The following object-like definition causes the preprocessor to replace all subsequent instances of the identifier COUNT with the constant 1000: #define COUNT 1000 This definition would cause the preprocessor to change the following statement (if the statement appears after the previous definition): int arry[COUNT]; In the output of the preprocessor, the preceding statement would appear as: int arry[1000]; The following definition references the previously defined identifier COUNT: #define MAX_COUNT COUNT + 100 The preprocessor replaces each subsequent occurrence of MAX_COUNT with COUNT + 100, which the preprocessor then replaces with 1000 + 100. ═══ 9.2.2. Function-Like Macro Definition ═══ Function-like macro definition: An identifier followed by a parenthesized parameter list and the replacement tokens. White space cannot separate the identifier (which is the name of the macro) and the left parenthesis of the parameter list. A comma must separate each parameter. For portability, you should not have more than 31 parameters for a macro. Function-like macro invocation: An identifier followed by a parenthesized list of arguments. A comma must separate each argument. Once the preprocessor identifies a function-like macro invocation, argument substitution takes place. A parameter in the replacement code is replaced by the corresponding argument. Any macro invocations contained in the argument itself are completely replaced before the argument replaces its corresponding parameter in the replacement code. The following line defines the macro SUM as having two parameters a and b and the replacement tokens (a + b): #define SUM(a,b) (a + b) This definition would cause the preprocessor to change the following statements (if the statements appear after the previous definition): c = SUM(x,y); c = d * SUM(x,y); In the output of the preprocessor, the preceding statements would appear as: c = (x + y); c = d * (x + y); ═══ Examples of #define Directives ═══ /************************************************************************ * The following program contains two macro definitions and a macro invocation that references both of the defined macros: * ************************************************************************/ #include #define SQR(s) ((s) * (s)) #define PRNT(a,b) \ printf("value 1 = %d\n", a); \ printf("value 2 = %d\n", b) ; int main(void) { int x = 2; int y = 3; PRNT(SQR(x),y); } /************************************************************************ * After being interpreted by the preprocessor, the preceding program is replaced by code equivalent to the following: * ************************************************************************/ int main(void) { int x = 2; int y = 3; { printf("value 1 = %d\n", ( (x) * (x) ) ); printf("value 2 = %d\n", y); } } /************************************************************************ * Execution of this program produces the following output: value 1 = 4 value 2 = 3 * ************************************************************************/ ═══ 9.3. #undef ═══ A preprocessor undef directive causes the preprocessor to end the scope of a preprocessor definition. A preprocessor #undef directive has the form: ──#──undef──identifier── #undef is ignored if the identifier is not currently defined as a macro. Once defined, a preprocessor identifier remains defined and in scope (independent of the scoping rules of the language) until the end of a translation unit or until it is undefined by an #undef preprocessor directive. You can also use the /U compiler option to undefine macros. The /U option does not undefine macros defined in source code. Examples of #undef Directives Related Information o #define o Predefined Macros o /U option o Preprocessor Directives ═══ Examples of #undef Directives ═══ The following directives define BUFFER and SQR: #define BUFFER 512 #define SQR(x) ((x) * (x)) The following directives nullify the preceding definitions: #undef BUFFER #undef SQR Any occurrences of the identifiers BUFFER and SQR that follow these #undef directives are not replaced with any replacement tokens. Once the definition of a macro has been removed by an #undef directive, the identifier can be used in a new #define directive. ═══ 9.4. Predefined Macros ═══ Both C and C++ provide the following predefined macro names as specified in the ANSI language standard: __LINE__ An integer representing the current source line number. __FILE__ A character string literal containing the name of the source file. __DATE__ A character string literal containing the date when the source file was compiled. The date will be in the form: "Mmm dd yyyy" where: Mmm represents the month in an abbreviated form (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, or Dec). dd represents the day. If the day is less than 10, the first d will be a blank character. yyyy represents the year. __TIME__ A character string literal containing the time when the source file was compiled. The time will be in the form: "hh:mm:ss" where: hh represents the hour. mm represents the minutes. ss represents the seconds. __STDC__ The integer 1. Note: This macro is undefined if the language level is set to anything other than ANSI. The SAA C standard reserves the following predefined macro names. The C/C++Tools implementation of the C++ language also provides these predefined macros: __TIMESTAMP__ A character string literal containing the date and time when the source file was last modified. The date and time will be in the form: "Day Mmm dd hh:mm:ss yyyy" where: Day represents the day of the week (Mon, Tue, Wed, Thu, Fri, Sat, or Sun). Mmm represents the month in an abbreviated form (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, or Dec). dd represents the day. If the day is less than 10, the first d will be a blank character. hh represents the hour. mm represents the minutes. ss represents the seconds. yyyy represents the year. __ANSI__ Allows only language constructs that conform to ANSI C standards. Defined using the #pragma langlvl directive or /Sa option. __SAA__ Allows only language constructs that conform to the most recent level of SAA C standards. Defined using the #pragma langlvl directive or /S2 option. This macro is not supported for C++. __SAAL2__ Allows only language constructs that conform to SAA Level 2 C standards. Defined using the #pragma langlvldirective or /S2 option. This macro is not supported for C++. __EXTENDED__ Allows additional language constructs provided by the implementation. Defined using the #pragma langlvl directive or /S2 option. The C/C++ Tools compiler provides several other predefined macros, described in Additional C/C++ Tools Predefined Macros. The value of __LINE__ will change during compilation as the compiler processes subsequent lines of your source program. Also, the value of __FILE__, and __TIMESTAMP__ will change as the compiler processes any #include files that are part of your source program. Predefined macro names cannot be the subject of a #define or #undef preprocessor directive. However, they can be undefined on the command line using the /U option, with the exception of the __DATE__, __FUNCTION__, __LINE__, __TIME__, and __TIMESTAMP__ macros. Examples of Predefined Macros Related Information o Additional C/C++ Tools Predefined Macros o #pragma langlvl o #define o #undef o /S2 option o Using Compiler Options ═══ 9.4.1. Additional C/C++ Tools Predefined Macros ═══ The macros identified in this section are provided to allow customers to write programs that use C/C++ Tools services. Only those macros identified in this section should be used to request or receive C/C++ Tools services. The additional macros offered by the C/C++ Tools compiler are: _CHAR_UNSIGNED Indicates default character type is unsigned. Defined using the #pragma chars directive or /J compiler option. _CHAR_SIGNED Indicates default character type is signed. Defined using the #pragma chars directive or /J compiler option. __COMPAT__ Indicates language constructs compatible with earlier versions of the C++ language are allowed. Defined using the #pragma langlvl(compat) directive or /Sc compiler option. This macro is valid for C++ programs only. __cplusplus Set to the integer 1. Indicates the product is a C++ compiler. This macro is valid for C++ programs only. __DBCS__ Indicates DBCS support is enabled. Defined using the /Sn compiler option. __DDNAMES__ Indicates ddnames are supported. Defined using the /Sh compiler option. __DLL__ Indicates code for a DLL is being compiled. Defined using the /Ge- compiler option. __FUNCTION__ Indicates the name of the function currently being compiled. For C++ programs, expands to the actual function prototype. __IBMC__ Indicates the version number of the C/C++ Tools C compiler. __IBMCPP__ Indicates the version number of the C/C++ Tools C++ compiler. _M_I386 Indicates code is being compiled for a 386 chip or higher. __MULTI__ Indicates multithread code is being generated. Defined using the /Gm compiler option. __OS2__ Set to the integer 1. Indicates the product is an OS/2 compiler. __SPC__ Indicates the subsystem libraries are being used. Defined using the /Rn compiler option. __TEMPINC__ Indicates the template-implementation file method of resolving template functions is being used. Defined using the /Ft compiler option. __TILED__ Indicates tiled memory is being used. Defined using the /Gt compiler option. __32BIT__ Set to the integer 1. Indicates the product is a 32-bit compiler. The value of the __IBMC__ and __IBMCPP__ macros is 200; these two macros are always defined. The macros __OS2__, _M_I386, and __32BIT__ are always defined also. The remaining macros, with the exception of __FUNCTION__, are defined when the corresponding #pragma directive or compiler option is used. Related Information o Predefined Macros o #pragma chars o #pragma langlvl o Code Generation Options o Source Code Options o Other Options o Using Compiler Options ═══ Example of Predefined Macros ═══ /************************************************************************ * The following printf statements will display the values of the predefined macros __LINE__, __FILE__, __TIME__, and __DATE__ and will print a message indicating the program's conformance to ANSI standards based on __STDC__: * ************************************************************************/ #pragma langlvl(ANSI) #include #ifdef __STDC__ # define CONFORM "conforms" #else # define CONFORM "does not conform" #endif int main(void) { printf("Line %d of file %s has been executed\n", __LINE__, __FILE__); printf("This file was compiled at %s on %s\n", __TIME__, __DATE__); printf("This program %s to ANSI standards\n", CONFORM); } ═══ 9.5. # Operator ═══ The # (single number sign) operator is used to convert a parameter of a function-like macro (see Function-Like Macro Definition) into a character string literal. If macro ABC is defined using the following directive: #define ABC(x) #x all subsequent invocations of the macro ABC would be expanded into a character string literal containing the argument passed to ABC. For example: ┌──────────────────────┬───────────────────────────┐ │ INVOCATION │ RESULT OF MACRO EXPANSION │ ├──────────────────────┼───────────────────────────┤ │ "ABC(1)" │ "1" │ ├──────────────────────┼───────────────────────────┤ │ "ABC(Hello there)" │ "Hello there" │ └──────────────────────┴───────────────────────────┘ The # operator should not be confused with the null directive. When you use the # operator in a function-like macro definition, the following rules apply: 1. A parameter in a function-like macro that is preceded by the # operator will be converted into a character string literal containing the argument passed to the macro. 2. White-space characters that appear before or after the argument passed to the macro will be deleted. 3. Multiple white-space characters imbedded within the argument passed to the macro will be replaced by a single space character. 4. If the argument passed to the macro contains a string literal and if a \ (backslash) character appears within the literal, a second \ character will be inserted before the original \ when the macro is expanded. 5. If the argument passed to the macro contains a " (double quotation mark) character, a \ character will be inserted before the " when the macro is expanded. 6. The conversion of an argument into a string literal occurs before macro expansion on that argument. 7. If more than one ## operator or # operator appears in the replacement list of a macro definition, the order of evaluation of the operators is not defined. 8. If the result of the replacement is not a valid character string literal, the behavior is undefined. Examples of the # Operator Related Information o #define o #undef o ## Operator o Function-Like Macro Definition o Preprocessor Directives ═══ Examples of the # Operator ═══ The following examples demonstrate the rules given in the preceding paragraph. #define STR(x) #x #define XSTR(x) STR(x) #define ONE 1 ┌──────────────────────┬───────────────────────────┐ │ INVOCATION │ RESULT OF MACRO EXPANSION │ ├──────────────────────┼───────────────────────────┤ │ "STR(\n "\n" '\n')" │ ""\n \"\\n\" '\\n'"" │ ├──────────────────────┼───────────────────────────┤ │ "STR(ONE)" │ "ONE" │ ├──────────────────────┼───────────────────────────┤ │ "XSTR(ONE)" │ "1" │ ├──────────────────────┼───────────────────────────┤ │ "XSTR("hello")" │ "\"hello\"" │ └──────────────────────┴───────────────────────────┘ ═══ 9.6. ## Operator ═══ The ## (double number sign) operator is used to concatenate two tokens in a macro invocation (text and/or arguments) given in a macro definition. If a macro XY was defined using the following directive: #define XY(x,y) x##y the last token of the argument for x will be concatenated with the first token of the argument for y. For example, ┌─────────────────┬───────────────────────────┐ │ INVOCATION │ RESULT OF MACRO EXPANSION │ ├─────────────────┼───────────────────────────┤ │ "XY(1, 2)" │ "12" │ ├─────────────────┼───────────────────────────┤ │ "XY(Green, │ "Greenhouse" │ │ house)" │ │ └─────────────────┴───────────────────────────┘ When you use the ## operator, the following rules apply: 1. The ## operator cannot be the very first or very last item in the replacement list of a macro definition. 2. The last token of the item preceding the ## operator is concatenated with first token of the item following the ## operator. 3. Concatenation takes place before any macros in arguments are expanded. 4. If the result of a concatenation is a valid macro name, it is available for further replacement even if it appears in a context in which it would not normally be available. 5. If more than one ## operator and/or # operator appears in the replacement list of a macro definition, the order of evaluation of the operators is not defined. Examples of the ## Operator Related Information o #define o #undef o # Operator o Preprocessor Directives ═══ Examples of the ## Operator ═══ The following examples demonstrate the rules for the ## operator: #define ArgArg(x, y) x##y #define ArgText(x) x##TEXT #define TextArg(x) TEXT##x #define TextText TEXT##text #define Jitter 1 #define bug 2 #define Jitterbug 3 ┌──────────────────────┬───────────────────────────┐ │ INVOCATION │ RESULT OF MACRO EXPANSION │ ├──────────────────────┼───────────────────────────┤ │ "ArgArg(var, 1)" │ ""var1"" │ ├──────────────────────┼───────────────────────────┤ │ "ArgText(var)" │ ""varTEXT"" │ ├──────────────────────┼───────────────────────────┤ │ "TextArg(var)" │ ""TEXTvar"" │ ├──────────────────────┼───────────────────────────┤ │ "TextText" │ ""TEXTtext"" │ ├──────────────────────┼───────────────────────────┤ │ "ArgArg(Jitter, │ "3" │ │ bug)" │ │ └──────────────────────┴───────────────────────────┘ ═══ 9.7. #error ═══ A preprocessor error directive causes the preprocessor to generate an error message and causes the compilation to fail. #error directive has the form: ┌───────────┐  │ >>───#───error────character─┴──>< The following directive generates the error message, Error in TESTPGM1 - This section should not be compiled: #error Error in TESTPGM1 - This section should not be compiled You can use the #error directive as a safety check during compilation. For example, if your program uses preprocessor conditional compilation directives (see Conditional Compilation), you can place #error directives in the source file to make the compilation fail if a section of the program is reached that should be bypassed. ═══ 9.8. #include ═══ A preprocessor include directive causes the preprocessor to replace the directive with the contents of the specified file. A preprocessor #include directive has the form: >>───#───include──┬─"file_name"─┬──>< ├─┐file_name>─┤ └─characters──┘ If the file name is enclosed in double quotation marks, for example: #include "payroll.h" the preprocessor treats it as a user-defined file, and searches for the file in the following places in the order given: 1. The directory where the original .c source file resides. 2. Any directories specified using the /I compiler option (that have not been removed by the /Xc option). Directories specified in the ICC environment variable are searched before those specified on the command line. 3. Any directories specified using the INCLUDE environment variable, provided the /Xi option is not in effect. If the file name is enclosed in angle brackets, for example: #include it is treated as a system-defined file, and the preprocessor searches the following places in the order given: 1. Any directories specified using the /I compiler option (that have not been removed by the /Xc option). Directories specified in the ICC environment variable are searched before those specified on the command line. 2. Any directories specified using the INCLUDE environment variable, provided the /Xi option is not in effect. Note: If the file name is fully qualified, the preprocessor searches only the directory specified by the name. The preprocessor resolves macros on a #include directive. After macro replacement, the resulting token sequence must consist of a file name enclosed in either double quotation marks or the characters < and >. For example: #define MONTH #include MONTH If there are a number of declarations used by several files, you can place all these definitions in one file and #include that file in each file that uses the definitions. For example, the following file defs.h contains several definitions and an inclusion of an additional file of declarations: /* defs.h */ #define TRUE 1 #define FALSE 0 #define BUFFERSIZE 512 #define MAX_ROW 66 #define MAX_COLUMN 80 int hour; int min; int sec; #include "mydefs.h" You can embed the definitions that appear in defs.h with the following directive: #include "defs.h" One of the ways you can combine the use of preprocessor directives is demonstrated in the following example. A #define is used to define a macro that represents the name of the C standard I/O header file. A #include is then used to make the header file available to the C program. #define IO_HEADER . . . #include IO_HEADER /* equivalent to specifying #include */ . . . Note: The new-line and > characters cannot appear in a file name delimited by < and >. The new-line and " (double quotation marks) character cannot appear in a file name delimited by " and ", although > can. Related Information o #define o Preprocessor Directives o Include Files ═══ 9.9. Conditional Compilation ═══ A preprocessor conditional compilation directive causes the preprocessor to conditionally suppress the compilation of portions of source code. Such directives test a constant expression or an identifier to determine which tokens the preprocessor should pass on to the compiler and which tokens should be ignored. The directives are: o #if o #ifdef o #ifndef o #else o #elif o #endif The preprocessor conditional compilation directive spans several lines: o The condition specification line o Lines containing code that the preprocessor passes on to the compiler if the condition evaluates to a nonzero value (optional) o The #else line (optional) o Lines containing code that the preprocessor passes on to the compiler if the condition evaluates to zero (optional) o The preprocessor #endif directive For each #if, #ifdef, and #ifndef directive, there are zero or more #elif directives, zero or one #else directive, and one matching #endif directive. All the matching directives are considered to be at the same nesting level. You can have nested conditional compilation directives. So if you have the following directives, the first #else will be matched with the #if directive. #ifdef MACNAME /* tokens added if MACNAME is defined */ # if TEST <=10 /* tokens added if MACNAME is defined and TEST <= 10 */ # else /* tokens added if MACNAME is defined and TEST > 10 */ # endif #else /* tokens added if MACNAME is not defined */ #endif Each directive controls the block immediately following it. A block consists of all the tokens starting on the line following the directive and ending at the next conditional compilation directive at the same nesting level. Each directive is processed in the order in which it is encountered. If an expression evaluates to zero, the block following the directive is ignored. When a block following a preprocessor directive is to be ignored, the tokens are examined only to identify preprocessor directives within that block so that the conditional nesting level can be determined. All tokens other than the name of the directive are ignored. Only the first block whose expression is nonzero is processed. The remaining blocks at that nesting level are ignored. If none of the blocks at that nesting level has been processed and there is a #else directive, the block following the #else directive is processed. If none of the blocks at that nesting level has been processed and there is no #else directive, the entire nesting level is ignored. Examples of Conditional Compilation Related Information o #if o #ifdef o #ifndef o #elif o #else o #endif o Preprocessor Directives ═══ 9.9.1. #if, #elif ═══ The #if and #elif directives compare the value of the expression to zero. All macros are expanded, any defined() expressions are processed and all remaining identifiers are replaced with the token 0. The preprocessor #if directive has the following form: ┌───────────┐  │ >>───#───if──constant_expression────statement─┴──>< The preprocessor #elif directive has the following form: ┌───────────┐  │ >>───#───elif──constant_expression────statement─┴──>< The expressions that are tested must be integer constant expressions that follow these rules: o No casts are performed. o The expression can contain the defined unary operator. The constant expression can contain the unary operator defined. This operator can be used only with the preprocessor keyword #if. The following expressions evaluate to 1 if the identifier is defined in the preprocessor, otherwise to 0: defined identifier defined(identifier) o The expression can contain defined macros. If a macro is not defined, a value of 0 is assigned to it. o Any arithmetic is performed using long ints. If the constant expression evaluates to a nonzero value, the tokens that immediately follow the condition are passed on to the compiler. Example of #if and #elif Directives Related Information o Conditional Compilation o #ifdef o #ifndef o #endif o Preprocessor Directives o if ═══ Examples of #if and #elif Directives ═══ /************************************************************************ * The following example uses the #if and #elif directives to assign values to an array. * ************************************************************************/ #include int main(void) { int i; char *arrayname = "realarray"; int realarray[] = { 1, 2, 3 }; int array1[] = { 4, 5, 6 }; int array2[] = { 7, 8, 9 }; #if ( (defined(LEVEL1)) && (TEST > 1) ) for (i = 0; i < 3; i++) realarray[i] = array1[i]; arrayname = "array1"; #elif (defined(LEVEL2)) for (i = 0; i < 3; i++) realarray[i] = array2[i]; arrayname = "array2"; #endif printf("realarray[] now has the contents of %s[]\n", arrayname); /* Assuming only LEVEL2 is defined, the expected output is: realarray[] now has the contents of array2[] */ } ═══ 9.9.2. #ifdef ═══ The #ifdef directive checks for the existence of macro definitions. If the identifier specified is defined as a macro, the tokens that immediately follow the condition are passed on to the compiler. The preprocessor #ifdef directive has the following form: ┌───────────┐  │ >>───#───ifdef──identifier────statement─┴──>< The following example defines MAX_LEN to be 75 if EXTENDED is defined for the preprocessor. Otherwise, MAX_LEN is defined to be 50. #ifdef EXTENDED # define MAX_LEN 75 #else # define MAX_LEN 50 #endif Related Information o Conditional Compilation o #ifndef o #if, #elif o #else o #endif o #define o #undef o Preprocessor Directives ═══ 9.9.3. #ifndef ═══ The #ifndef directive checks for the existence of macro definitions. If the identifier specified is not defined as a macro, the tokens that immediately follow the condition are passed on to the compiler. The preprocessor #ifndef directive has the following form: ┌───────────┐  │ >>───#───ifndef──identifier────statement─┴──>< The following example defines MAX_LEN to be 50 if EXTENDED is not defined for the preprocessor. Otherwise, MAX_LEN is defined to be 75. #ifndef EXTENDED # define MAX_LEN 50 #else # define MAX_LEN 75 #endif Related Information o Conditional Compilation o #ifdef o #if, #elif o #else o #endif o #define o #undef o Preprocessor Directives ═══ 9.9.4. #else ═══ If the condition specified in the #if, #ifdef, or #ifndef directive evaluates to 0, and the conditional compilation directive contains a preprocessor #else directive, the source text located between the preprocessor #else directive and the preprocessor #endif directive is selected by the preprocessor to be passed on to the compiler. The preprocessor #else directive has the form: ┌───────────┐  │ >>───#───else────statement─┴──>< The following example defines MAX_LEN to be 50 if EXTENDED is not defined for the preprocessor. Otherwise, MAX_LEN is defined to be 75. #ifndef EXTENDED # define MAX_LEN 50 #else # define MAX_LEN 75 #endif Related Information o Conditional Compilation o #if, #elif o #ifdef o #ifndef o #endif o #define o Preprocessor Directives ═══ 9.9.5. #endif ═══ The preprocessor #endif directive ends the conditional compilation directive. The preprocessor #endif directive has the form: ┌────────────────────┐  │ >>───#───pragma────character_sequence─┴──>< The following example shows preprocessor conditional compilation directives ended by the #endif directive. #if defined(LEVEL1) # define SIZEOF_INT 16 # ifdef PHASE2 # define MAX_PHASE 2 # else # define MAX_PHASE 8 # endif #elif defined(LEVEL2) # define SIZEOF_INT 32 # define MAX_PHASE 16 #endif Related Information o Conditional Compilation o #if, #elif o #ifdef o #ifndef o #else o Preprocessor Directives ═══ Examples ═══ /************************************************************************ * The following example shows how you can nest preprocessor conditional compilation directives: #if defined(TARGET1) # define SIZEOF_INT 16 # ifdef PHASE2 # define MAX_PHASE 2 # else # define MAX_PHASE 8 # endif #elif defined(TARGET2) # define SIZEOF_INT 32 # define MAX_PHASE 16 #else # define SIZEOF_INT 32 # define MAX_PHASE 32 #endif The following program contains preprocessor conditional compilation directives: * ************************************************************************/ #include int main(void) { static int array[ ] = { 1, 2, 3, 4, 5 }; int i; for (i = 0; i <= 4; i++) { array[i] *= 2; #if TEST >= 1 printf("i = %d\n", i); printf("array[i] = %d\n", array[i]); #endif } } ═══ 9.10. #line ═══ A preprocessor line control directive causes the compiler to view the line number of the next source line as the specified number. A preprocessor #line directive has the form: >>───#───line──┬─decimal_constant──┬─────────────┬─┬──>< │ └─"file_name"─┘ │ └─characters────────────────────────┘ A file name specification enclosed in double quotation marks can follow the line number. If you specify a file name, the compiler views the next line as part of the specified file. If you do not specify a file name, the compiler views the next line as part of the current source file. The token sequence on a #line directive is subject to macro replacement. After macro replacement, the resulting character sequence must consist of a decimal constant, optionally followed by a file name enclosed in double quotation marks. You can use #line control directives to make the compiler provide more meaningful error messages. Example of #line Directives Related Information o Preprocessor Directives o Decimal Constants ═══ Example of #line Directives ═══ /************************************************************************ * The following program uses #line control directives to give each function an easily recognizable line number: * ************************************************************************/ #include #define LINE200 200 int main(void) { func_1(); func_2(); } #line 100 func_1() { printf("Func_1 - the current line number is %d\n",_ _LINE_ _); } #line LINE200 func_2() { printf("Func_2 - the current line number is %d\n",_ _LINE_ _); } /************************************************************************ * The preceding program produces the following output: Func_1 - the current line number is 102 Func_2 - the current line number is 202 * ************************************************************************/ ═══ 9.11. # (Null Directive) ═══ The null directive performs no action. The null directive consists of a single # on a line of its own. The null directive should not be confused with the # operator or the character that starts a preprocessor directive. In the following example, if MINVAL is a defined macro name, no action is performed. If MINVAL is not a defined identifier, it is defined 1. #ifdef MINVAL # #else #define MINVAL 1 #endif Related Information o Preprocessor Directives o Null Statement ═══ 9.12. #pragma ═══ A pragma is an implementation-defined instruction to the compiler. It has the general form given below, where character sequence is a series of characters giving a specific compiler instruction and arguments, if any. ┌──────────────────────┐  │ ──#──pragma─────character_sequence──┴── The character sequence on a pragma is not subject to macro substitutions. More than one pragma construct can be specified on a single #pragma directive. The following pragmas are available: o alloc_text o chars o checkout o comment o data_seg o define o entry o export o handler o implementation o import o info o langlvl o linkage o map o margins o pack o page o pagesize o priority o seg16 o sequence o skip o sourcedir o stack16 o strings o subtitle o title o undeclared Examples of #pragma directives Related Information o #pragma Restrictions o Preprocessor Directives ═══ 9.12.1. #pragma Restrictions ═══ Some #pragma directives must appear in a certain place in your source, or can appear a limited number of times. The following table lists the restrictions for #pragma directives. ┌──────────────────────────────────────────────────────────────────────────────┐ │ #pragma Restrictions │ ├──────────┬────────────────────────┬──────────────────────────────────────────┤ │ #PRAGMA │ RESTRICTION OF PLACE- │ RESTRICTION ON NUMBER OF OCCURRENCES │ │ │ MENT │ │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ chars │ On the first #pragma │ Once │ │ │ directive, and before │ │ │ │ any code or directive │ │ │ │ (except "#line") │ │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ comment │ "copyright" directive │ "compiler" and "timestamp" directives │ │ │ must appear before any │ can appear only once │ │ │ code │ │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ entry │ No restriction │ Once │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ langlvl │ On the first #pragma │ Once │ │ │ directive, and before │ │ │ │ any code or directive │ │ │ │ (except "#line") │ │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ linkage │ Before any declaration │ Once for each function │ │ │ of or call to the │ │ │ │ function │ │ ├──────────┼────────────────────────┼──────────────────────────────────────────┤ │ strings │ Before any code │ Once │ └──────────┴────────────────────────┴──────────────────────────────────────────┘ Related Information o #pragma chars o #pragma comment o #pragma entry o #pragma langlvl o #pragma linkage o #pragma strings o #line o #pragma ═══ 9.12.2. alloc_text ═══ The #pragma alloc_text directive lets you group functions into different 32-bit code segments. ┌─────────────┐  │ >>──#──pragma──alloc_text──(──codesegment────,──function─┴──)──>< The codesegment is the name of the code segment where you want to place function. You can specify any number of functions to be included in the named codesegment. Functions that are not grouped in a code segment by #pragma alloc_text are placed in the default 32-bit code segment CODE32. You can also use #pragma alloc_text to explicitly place functions in CODE32 by specifying it as the codesegment. Defining your own code segments allows you to organize functions in memory so that the working set requires fewer pages of memory. You can also specify attributes for each segment, such as execute-only or preload. You specify attributes for code segments in a module definition (.DEF) file. For example, to create two code segments, one load on call, the other preload: #pragma alloc_text(pl_seg, func1) #pragma alloc_text(loc_seg, func2) and use the following statement in the .DEF file for the program: SEGMENTS pl_seg PRELOAD For more information on attributes and how to specify them in a .DEF file, see the Toolkit documentation for the LINK386 program. Related Information o #pragma data_seg o #pragma o Preprocessor Directives ═══ 9.12.3. chars ═══ Specifies that the compiler is to treat all char objects as signed or unsigned. This pragma must appear before any statements in a file. >>───#───pragma──chars──(──┬─signed───┬──)──>< └─unsigned─┘ Related Information o Characters o #pragma o Preprocessor Directives ═══ 9.12.4. checkout ═══ The #pragma checkout directive controls the diagnostic messages generated by the /Kn compiler options. Note: This #pragma directive is valid for C code only. >>───#───pragma──checkout──(──┬─resume──┬──)──>< └─suspend─┘ Use #pragma checkout to suspend the diagnostics performed by the /Kn options during specific portions of your program, and then resume the same level of diagnostics at some later point in the file. Note: The /Wgrp options have been added to provide greater control over diagnostic messages. The C/C++ Tools C compiler maps the /Kn options to the appropriate /Wgrp option. It also maps #pragma checkout to #pragma info. The C/C++ Tools C++ compiler maps the /Kn options, but ignores #pragma checkout directives. Because support for the /Kn options and #pragma checkout will eventually be removed from C/C++ Tools, you should avoid using them in any new code. Nested #pragma checkout directives are allowed and behave as follows: /* Assume /Kpx has been specified */ #pragma checkout(suspend) /* No diagnostics are performed */ . . . #pragma checkout(suspend) /* No effect */ . . . #pragma checkout(resume) /* No effect */ . . . #pragma checkout(resume) /* Diagnostics continue */ The #pragma checkout directive affects all /Kn options specified. Related Information o /Kn Options o Using the /Wgrp Diagnostic Options o #pragma info o #pragma o Preprocessor Directives ═══ 9.12.5. comment ═══ Emits a comment into the object file. >>───#───pragma──comment──(──┬─compiler─────────────────────────┬──)──>< ├─date─────────────────────────────┤ ├─timestamp────────────────────────┤ └─┬─copyright─┬──┬───────────────┬─┘ └─user──────┘ └─,"characters"─┘ The comment type can be: compiler the name and version of the compiler is emitted into the end of the generated object module. date the date and time of compilation is emitted into the end of the generated object module. timestamp the last modification date and time of the source is emitted into the end of the generated object module. copyright the text specified by the character field is placed by the compiler into the generated object module and is loaded into memory when the program is run. user the text specified by the character field is placed by the compiler into the generated object but is not loaded into memory when the program is run. Related Information o #pragma o Preprocessor Directives ═══ 9.12.6. data_seg ═══ The #pragma data_seg directive lets you place static and external variables in different 32-bit data segments. >>───#───pragma──data_seg──(──datasegment──)──>< All static and external variables defined after the #pragma data_seg directive are placed in the named datasegment until another #pragma data_seg statement is found or the end of the compilation unit is reached. Restrictions: o Writable string literals used to initialize pointers are not placed in the named datasegment, but in the default 32-bit data segment (DATA32). To place a string in a particular data segment, use an array to initialize the string instead of a pointer. For example: char a[ ] = "mystring"; instead of char *a = "mystring"; o #pragma data_seg applies only to 32-bit data segments. Data placed in 16-bit segments because of the /Gt option or #pragma seg16 are not affected by #pragma data_seg, and are placed in 16-bit data segments. Static and external variables defined before the first #pragma data_seg directive are placed in the default DATA32 segment, with the exception of uninitialized variables and variables explicitly initialized to zero, which are placed in the BSS32 segment. You can also use #pragma data_seg to explicitly place variables in the DATA32 segment by specifying no datasegment, for example, #pragma data_seg(). However, you cannot use the CONST or BSS32 segments in a #pragma data_seg directive. Note: Because the variables in the BSS32 data segment are initialized at load time and loaded separately from the rest of your program, they take less space in your executable file. If you place these variables in a different data segment, this optimization does not take place, and the size of your executable module increases. For this reason, if the size of your executable file is critical to you, you should define all variables initialized to zero (either explicitly or by default) before the first occurrence of #pragma data_seg. Defining your own data segments allows you to group data depending on how it is used and to specify different attributes for different groups of data, such as when the data should be loaded. You specify attributes for data segments in a module definition (.DEF) file. For example, when you build a DLL, you might have one set of data that you want to make global for all processes that use the DLL, and a different set of data that you want to copy for each process. You could use #pragma data_seg to place the data in two different segments as follows: #pragma data_seg(globdata) static int counter1 = 0; static int counter2 = 0; . . . #pragma data_seg(instdata) static int instcount1 = 0; static int instcount2 = 0; . . . You could then place the following statements in the program's .DEF file: SEGMENTS globdata CLASS 'DATA' SHARED instdata CLASS 'DATA' NONSHARED SHARED specifies that the data in the globdata segment is global or shared by all processes that use the DLL. NONSHARED means that each process gets its own copy of the data in the instdata segment. For more information on attributes and how to specify them in a .DEF file, see the Toolkit documentation for the LINK386 program. Related Information o #pragma alloc_text o #pragma o Preprocessor Directives ═══ 9.12.7. define ═══ The #pragma define can be used to force the definition of a template class without actually defining an object of the class. This directive is valid for C++ files only. The syntax is: >>──#──pragma──define──(──template_class_name──)──>< The pragma can appear anywhere that a declaration is allowed. The define pragma is used when organizing your program for the efficient or automatic generation of template functions. "Using Templates in C++ Programs" in the IBM C/C++ Tools: Programming Guide gives more information about using #pragma define. Related Information o Templates o #pragma o Preprocessor Directives o "Using Templates in C++ Programs" in the Programming Guide ═══ 9.12.8. entry ═══ The #pragma entry directive specifies the function to be used as the entry point for the application being built. >>───#───pragma──entry──(──func_name──)──>< The func_name function must be in the same compilation unit as the #pragma entry directive, and must be a defined external function. Normally when an application is started, the OS/2 system calls the C library entry point. When you specify a different entry point using #pragma entry, the system calls that entry point and does not perform any C library initialization or termination. If you use #pragma entry, you must ensure that your executable file does not require library initialization or termination, or you must provide your own initialization and termination functions. Related Information o #pragma o Preprocessor Directives ═══ 9.12.9. export ═══ The #pragma export directive declares that a DLL function is to be exported and specifies the name of the function outside the DLL. >>───#──pragma─export──(──function_name──,──┬───────────────────┬──,──> └─"──export_name──"─┘ >──ordinal──)──>< The function_name is the name of the function in the DLL. The export_name is the name for function outside of the DLL. If no export_name is specified, function is used. The ordinal is the number of the function within the DLL. Another module can import the function using either the export_name or the ordinal number. Ordinal numbers are described in more detail in the Toolkit documentation. For example, the statements: int elaine(int); #pragma export(elaine, catherine, 4) declare that the function elaine is to be exported, and can be imported by another module using the name catherine or the ordinal number 4. See #pragma import for information on importing functions. You can also use the _Export keyword to export a function. If you use the keyword, you cannot specify a different name or an ordinal for the exported function. If you use #pragma export to export your function, you may still need to provide an EXPORTS entry for that function in your module definition (.DEF) file. If your function has any of the following default characteristics o Has shared data o Has no I/O privileges o Is not resident it does not require an EXPORTS entry. If your function has characteristics other than the defaults, the only way you can specify them is with an EXPORTS entry in your .DEF file. Note: To create an import library for the DLL, you must either create it from the DLL itself or provide a .DEF file with an EXPORTS entry for every function, regardless of whether #pragma export is used. For more information on DLLs and .DEF files, see the Programming Guide. Related Information o #pragma import o _Export Qualifier o #pragma o Preprocessor Directives ═══ 9.12.10. handler ═══ The #pragma handler directive registers an exception handler for a function. >>───#───pragma──handler──(──function──)──>< The function is the name of the function for which the exception handler is to be registered. You should declare it before you use it in this directive. The #pragma handler directive generates the code at compile time to install the C/C++Tools exception handler _Exception before starting execution of the function. It also generates code to remove the exception handler at function exit. You must use this directive whenever you change library environments or enter a user-created DLL. Note: If you are using the subsystem libraries, the _Exception function is not provided. To use the #pragma handler directive in a subsystem, you must provide your own exception handler named _Exception. Otherwise, you must register and remove your own exception handlers using the OS/2 exception handler APIs described in the IBM OS/2 2.0 Programming Reference. For more information on exception handling and _Exception, see the IBM C/C++ Tools: Programming Guide. Related Information o #pragma o Preprocessor Directives ═══ 9.12.11. implementation ═══ The implementation pragma is used to tell the compiler the name of the file that contains the function template definitions corresponding to the template declarations in the include file containing the pragma. This directive is valid for C++ files only. The syntax is: >>──#──pragma──implementation──(──string_literal──)──>< The pragma can appear anywhere that a declaration is allowed. The implementation pragma is used when organizing your program for the efficient or automatic generation of template functions. "Using Templates in C++ Programs" in the IBM C/C++ Tools: Programming Guide gives more information about using #pragma implementation. Related Information o Templates o #pragma o Preprocessor Directives o "Using Templates in C++ Programs" in the Programming Guide ═══ 9.12.12. import ═══ The #pragma import directive lets you import a function from a DLL using either an ordinal number or a function name different from the one that it has in the DLL. >>───#───pragma──import──(──function──,──┬─────────────────────┬──,──> └─"──external_name──"─┘ >──"──mod_name──"──,──ordinal──)──>< The function is the name you use in your source to call the function. The external_name is the name of the function in the DLL. For C++ files, external_name can also be a function prototype. If external_name is not specified, it is assumed to be the same as function. Note: Both function and external_name must be defined only once in each compilation unit. The mod_name is the name of the DLL containing the function, and ordinal indicates the position of the function within the DLL. Ordinal numbers are described in more detail in the Toolkit documentation. The information provided by #pragma import is used at load time to locate the imported function. If ordinal is 0, the external_name is used to find the function. If ordinal is any other number, external_name is ignored and the function is located by number. It is usually faster to locate the function by number than by name. Using #pragma import decreases your link time because the linker does not require an import library to resolve external names. This #pragma directive is also useful for C++ programming because you do not have to use the fully qualified function name to call an imported function. Note: You cannot use the ordinals provided in the Toolkit header files with #pragma import. These ordinals are provided as C macros that cannot be used in #pragma directives. Related Information o #pragma export o _Export Qualifier o #pragma o Preprocessor Directives ═══ 9.12.13. info ═══ The #pragma info directive controls the diagnostic messages generated by the /Wgrp compiler options. >>───#───pragma──info──(──┬─all─────────┬──)──>< ├─none────────┤ ├─restore─────┤ │ ┌─,───────┐ │ │  │ │ └──┬─grp───┬┴─┘ └─nogrp─┘ You can use this #pragma directive in place of the /Wgrp option to turn groups of diagnostics on or off. Specifying #pragma info(grp) causes all messages associated with that diagnostic group to be generated. Specifying #pragma info(nogrp) suppresses all messages associated with that group. For example, to generate messages for missing function prototypes and statements with no effect, but not for uninitialized variables, specify: #pragma info(pro, eff, nouni) The #pragma directive overrides any /Wgrp options stated on the command line. Use #pragma info(all) to turn on all diagnostic checking. You can use #pragma info(none) to turn off all diagnostic suboptions for specific portions of your program. Specifying #pragma info(restore) restores the options that were in effect before the previous #pragma info directive. Because #pragma info operates like a stack, the options restored may not be those given on the command line. If no options were previously in effect, #pragma info(restore) does nothing. The #pragma info directive replaces the #pragma checkout directive for controlling diagnostics. The C/C++ Tools compiler will map #pragma checkout(suspend) to #pragma info(none), and #pragma checkout(resume) to #pragma info(restore). The following list explains the groups of diagnostic messages controlled by each grp option: Group Diagnostics cmp Possible redundancies in unsigned comparisons. cnd Possible redundancies or problems in conditional expressions. cns Operations involving constants. cnv Conversions. dcl Consistency of declarations. eff Statements with no effect. enu Consistency of enum variables. ext Unused external definitions. gen General diagnostics. got Usage of goto statements. ini Possible problems with initialization. lan Effects of the language level. obs Features that are obsolete. ord Unspecified order of evaluation. par Unused parameters. por Nonportable language constructs. ppc Possible problems with using the preprocessor. ppt Trace of preprocessor actions. pro Missing function prototypes. rea Code that cannot be reached. ret Consistency of return statements. trd Possible truncation or loss of data or precision. tru Variable names truncated by the compiler. uni Uninitialized variables. use Unused auto and static variables. Related Information o #pragma checkout o Using the /Wgrp Diagnostic Options o Debugging and Diagnostic Information Options o #pragma o Preprocessor Directives ═══ 9.12.14. langlvl ═══ The #pragma langlvl directive lets you select elements of the C/C++ Tools implementation. ┌─extended─┐ >>───#───pragma──langlvl──(──┼─ansi─────┼──)──>< ├─compat───┤ ├─saa──────┤ └─saal2────┘ This directive can be specified only once in your source file, and must appear before any C code. The compiler defines preprocessor variables that are used in header files to define the language level. The options are: extended Defines the preprocessor variable __EXTENDED__. Allows ANSI and SAA C constructs and all C/C++ Tools extensions. ansi Defines the preprocessor variables __ANSI__ and __STDC__. Allows only language constructs that conform to ANSI standards. Note that for C++, the __STDC__ macro is set to 0, while for C it is set to 1. compat Defines the preprocessor variable __COMPAT__. Allows constructs supported by earlier versions of the C++ language, as well as ANSI constructs and C/C++ Tools extensions. This language level is valid for C++ programs only. saa Defines the preprocessor variables __SAA__ and __SAA_L2__. Allows only language constructs that conform to the most recent level of SAA C standards (currently Level 2). These include ANSI C constructs. This language level is valid for C programs only. saal2 Defines the preprocessor variable __SAA_L2__. Allows only language constructs that conform to SAA Level 2 C standards. These include ANSI C constructs. This language level is valid for C programs only. The default language level is extended. You can also set the language level using the /Sa, /Sc, /S2, and /Se compiler options. These options are described in Source Code Options. Related Information o /Sa, /Sc, /S2, /Se options o Predefined Macros o #pragma o Preprocessor Directives ═══ 9.12.15. linkage ═══ The #pragma linkage directive identifies the linkage or calling convention used on a function call. Note: This #pragma directive is valid for C code only. ┌─optlink──────────────┐ >>───#──pragma─linkage─(──identifier─,──┼─system───────────────┼──)──>< ├─┬───────┬──pascal────┤ │ └─far32─┘ │ └─far16──┬───────────┬─┘ ├─cdecl─────┤ ├─_cdecl────┤ ├─pascal────┤ ├─_pascal───┤ ├─fastcall──┤ └─_fastcall─┘ The identifier identifies either the name of the function that will be given the particular linkage type or the name of a typedef that resolves to a function type. If identifier is a typedef, any function declared using identifier will be given the particular linkage type. The following example shows how to use a typedef to declare functions and pointers to functions of _System linkage: #pragma linkage(functype, system) typedef int functype(int); functype f; /* f is a function with _System linkage */ functype *fp; /* fp is a pointer to a function with _System linkage */ The C/C++ Tools default linkage is _Optlink, which is a convention specific to the C/C++ Tools product. If your program calls OS/2 APIs, you must use the _System calling convention, which is standard for all OS/2 applications to call those APIs. If you include the system header files, the OS/2 APIs are automatically given _System linkage. If you are developing device drivers, you should use the _Pascal convention. You should use the _Far32 version of _Pascal linkage if your calls will cross code segments. Note that _Far32 _Pascal linkage is only available when you specify the /Gr+ option to generate code that runs at ring zero. The _Far16 linkage conventions indicate that a function has a 16-bit linkage type. The cdecl and _cdecl options are equivalent. The underscore is optional, and is accepted for compatibility with C/2* cdecl linkage declarations. Similarly, pascal and _pascal are equivalent, and specify C/2 pascal linkage; fastcall and _fastcall specify Microsoft** _fastcall linkage. If far16 is specified without a parameter, _Cdecl linkage is used. You can also use linkage keywords to specify the calling convention for a function. Linkage keywords are easier to use than is the #pragma linkage directive. They let you declare both the function and its linkage type in one statement. See Linkage Keywords for more information on these keywords. You can use compiler options to explicitly set the calling convention to _Optlink (/Mp) or to change the default to _System linkage (/Ms). These options are described in Code Generation Options. A linkage keyword or #pragma linkage directive overrides the compiler option. For more information about calling conventions, see the Programming Guide. Related Information o /Mp, /Ms Options o Linkage Keywords o typedef o #pragma o Preprocessor Directives ═══ 9.12.16. map ═══ The #pragma map directive associates an external name (name) with a C name (identifier). >>───#───pragma──map──(──identifier──,──"name"──)──>< The #pragma map directive is provided primarily for compatibility with IBM C/370. but can also be used with the C/C++ Tools debugger. It is also useful when your program maps to functions created by other compilers that precede identifier and function names with underscores. When you use this directive, the identifier that appears in the source file is not visible in the object file. The external name will be used to represent the object in the object file. Enclose the variable name in double quotation marks. The name will be kept as specified on the #pragma map directive in mixed case. Multiple identifiers can have the same map name. The compiler generates an error message if more than one map name is given to an identifier. The map name is an external name and must not be used in the source file to reference the object. If you try to use the map name in the source file, to access the corresponding object, the compiler will treat the map name as a new identifier. The compiler generates an error if a repeated #pragma map directive is encountered with the same map name and the same identifier. Note: The C/C++ Tools compiler does not implement the optional third parameter to #pragma map, as defined by the SAA standard. Related Information o #pragma o Preprocessor Directives ═══ 9.12.17. margins ═══ The #pragma margins directive specifies the columns in the input line that are to be scanned for input to the compiler. Note: This #pragma directive is valid for C code only. ┌─nomargins──────────────┐ >>───#───pragma──┴─margins──(──l──,──r──)─┴──>< Use the #pragma margins directive if you want to have characters outside certain columns ignored in your source file. The compiler ignores any text in the source input that does not fall within the range specified in the directive. The variable l specifies the first column of the source input that is to be scanned, and must be between 1 and 65535, inclusive. The variable r specifies the last column of the source input that is to be scanned. It must be greater than or equal to l and less than or equal to 65535. An asterisk (*) can be assigned to r to indicate the last column of input. By default, the left margin is set to 1, and the right margin is set to infinity. If nomargins is specified, the default values are taken. The #pragma margins directive can be used with the #pragma sequence directive to specify the columns that are not to be scanned for sequence numbers. If the #pragma sequence settings do not fall within the #pragma margins settings, the sequence directive has no effect. You can also set margins using the /Sg option. This option is described in Source Code Options. Related Information o /Sg Option o #pragma sequence o #pragma o Preprocessor Directives ═══ 9.12.18. pack ═══ The #pragma pack directive specifies the alignment rules to use for the structures and unions that follow it. >>───#───pragma──pack──(──┬───┬──)──>< ├─1─┤ ├─2─┤ └─4─┘ The #pragma pack directive causes all structures and unions that follow it in the program to be packed along a 1-byte, 2-byte, or 4-byte (the system default) boundary, according to the value specified in the directive, until another #pragma pack directive changes the packing boundary. If no value is specified, packing is performed along the system default boundary unless the /Sp compiler option was used. If it is used, #pragma pack() causes packing to be performed along the boundary specified by /Sp. The /Sp option is described in Source Code Options. For example: #pragma pack(1) struct hester{ /* this structure will be packed */ char philip; /* along 1-byte boundaries */ int mark; }; . . . #pragma pack(2) struct jeff{ /* this structure will be packed */ float bill; /* along 2-byte boundaries */ int *chris; } . . . #pragma pack() struct dor{ /* this structure will be packed */ double stephen; /* along the default boundaries */ long alex; } Note: If data types are by default packed along boundaries smaller than those specified by #pragma pack, they are still aligned along the smaller boundaries. For example, type char is always aligned along a 1-byte boundary, regardless of the value of #pragma pack. The following chart describes how each data type is packed for each of the #pragma pack options: ┌─────────────────┬─────────────────────────────┐ │ DATA TYPE │ #PRAGMA PACK VALUE │ ├─────────────────┼─────────┬─────────┬─────────┤ │ │ 1 │ 2 │ 4 │ ├─────────────────┼─────────┼─────────┼─────────┤ │ "char" │ 1 │ 1 │ 1 │ ├─────────────────┼─────────┼─────────┼─────────┤ │ "short" │ 1 │ 2 │ 2 │ ├─────────────────┼─────────┼─────────┼─────────┤ │ "int", "long" │ 1 │ 2 │ 4 │ ├─────────────────┼─────────┼─────────┼─────────┤ │ "float", │ 1 │ 2 │ 4 │ │ "double", "long │ │ │ │ │ double" │ │ │ │ ├─────────────────┼─────────┼─────────┼─────────┤ │ pointer │ 1 │ 2 │ 4 │ └─────────────────┴─────────┴─────────┴─────────┘ Note: The #pragma pack directive does not have the same effect as declaring a structure as _Packed. The _Packed keyword removes all padding from between structure members, while the #pragma pack directive only specifies the boundaries to align the members on. Although _Packed is a SAA C construct, it is not portable to many systems. The C++ language does not support it. If portability and C++ support are important to you, avoid using the _Packed qualifier. For more information on packing structures, see _Packed Qualifier. Related Information o /Sp Option o _Packed Qualifier o Structures o Types o #pragma o Preprocessor Directives ═══ 9.12.19. page ═══ Skips n pages of the generated source listing. If n is not specified, the next page is started. >>───#───pragma──page──(──┬───┬──)──>< └─n─┘ Related Information o #pragma o Preprocessor Directives ═══ 9.12.20. pagesize ═══ The #pragma pagesize directive sets the number of lines per page to n for the generated source listing. >>───#───pragma──pagesize──(──┬───┬──)──>< └─n─┘ The value of n must be between 16 and 32767, inclusive. The default page length is 66 lines. You can also use the /Lp compiler option to set the listing page size. This option is described in Listing File Options. Related Information o /Lp Option o #pragma o Preprocessor Directives ═══ 9.12.21. priority ═══ The priority pragma specifies the order in which static objects are to be initialized at run time. This directive is valid for C++ files only. The syntax is: >>──#──pragma──priority──(──n──)──>< where n is an integer literal in the range of INT_MIN to INT_MAX. The default value is 0. A negative value indicates a higher priority; a positive value indicates a lower priority. The first 1024 priorities (INT_MIN to INT_MIN + 1023) are reserved for use by the compiler and its libraries. The priority value specified applies to all runtime static initialization in the current compilation unit. Related Information o #pragma o Preprocessor Directives ═══ 9.12.22. seg16 ═══ The #pragma seg16 directive specifies that a data object will be shared between 16-bit and 32-bit processes. >>───#───pragma──seg16──(──identifier──)──>< It causes the compiler to lay out the identifier in memory so that it does not cross a 64K boundary. The identifier can then be used in a 16-bit program. The identifier can be a typedef or a data object. For example: typedef struct foo foostr; #pragma seg16(foostr) foostr quux; uses the typedef foostr to declare quux as an object addressable by a 16-bit program. You can also use the /Gt compiler option to perform the equivalent of a #pragma seg16 for all variables in the program. The /Gt option is described in Code Generation Options. Note: If #pragma seg16 is used on variables of a structure type, the pointers inside that structure are not automatically qualified as usable by 16-bit programs. If you want the pointers in the structure qualified as such, you must declare them using the _Seg16 type qualifier. See _Seg16 Type Qualifier for more information about _Seg16. For more information on calling 16-bit programs, see the Programming Guide. Related Information o /Gt Option o _Seg16 Type Qualifier o Structures o typedef o #pragma o Preprocessor Directives ═══ 9.12.23. sequence ═══ The #pragma sequence directive defines the section of the input line that is to contain sequence numbers. Note: This #pragma directive is valid for C code only. ┌─nosequence──────────────┐ >>───#───pragma──┴─sequence──(──l──,──r──)─┴──>< If you are using a source file produced on a system that uses sequence numbers, you can use this option to have the sequence numbers ignored. The variable l specifies the column number of the left-hand margin. The value of l must be between 1 and 65535 inclusive, and must also be less than or equal to the value of r. The variable r specifies the column number of the right-hand margin. The value of r must be greater than or equal to l and less than or equal to 65535. An asterisk (*) can be assigned to r to indicate the last column of the line. The default for this directive is nosequence, which specifies there are no sequence numbers. The #pragma sequence directive can be used with the #pragma margins directive to specify the columns that are not to be scanned. If the #pragma sequence settings do not fall within the #pragma margins settings, the sequence directive has no effect. You can also set sequence numbers using the /Sq option. This option is described in Source Code Options. Related Information o /Sq Option o #pragma margins o #pragma o Preprocessor Directives ═══ 9.12.24. skip ═══ Skips the next n lines of the generated source listing. The value of n must be a positive integer less than 255. If n is omitted, one line is skipped. >>───#───pragma──skip──(──┬───┬──)──>< └─n─┘ Related Information o #pragma o Preprocessor Directives o Listing File Options ═══ 9.12.25. sourcedir ═══ The sourcedir pragma defines a new path to the directory containing the original source from which the compiler generates files in the TEMPINC directory. >>───#───pragma──sourcedir──(──path──)──>< Instead of searching the TEMPINC directory first for the original source of the include file, the pragma directs the compiler to the directory specified by the supplied path. The compiler automatically inserts the necessary #pragma sourcedir directives into the source files it generates in the TEMPINC directory. Note: This directive can only be used in C++ code. Related Information o #pragma ═══ 9.12.26. stack16 ═══ The #pragma stack16 directive specifies the size of the stack to be allocated for calls to 16-bit routines. >>───#───pragma──stack16──(──┬──────┬──)──>< └─size─┘ The variable size is the size of the stack in bytes, and has a value between 512 and 65532. The size specified applies to any 16-bit functions called from that point until the end of the compilation unit, or until another #pragma stack16 directive is given. The default value is 4096 bytes (4K). Note that the 16-bit stack is taken from the 32-bit stack allocated for the thread calling the 16-bit code. The 32-bit stack is therefore reduced by the amount you specify with #pragma stack16. Make sure your 32-bit stack is large enough for both your 32-bit and 16-bit code. If the sum of the size, the number of bytes for parameters, and the number of local bytes in the function calling the 16-bit routine is greater than 65532, the actual stack size will be 65532 bytes less the number of parameter and local bytes. If the sum of the parameter bytes and local bytes alone is greater than 65532, no bytes will be allocated for calls to 16-bit routines. Related Information o #pragma o Preprocessor Directives ═══ 9.12.27. strings ═══ Specifies that the compiler may place strings into read-only memory or must place strings into writeable memory. Strings are writeable by default. This pragma must appear before any C or C++ code in a file. ┌─writeable─┐ >>───#───pragma──strings──(──┴─readonly──┴──)──>< Related Information o Strings o #pragma o Preprocessor Directives ═══ 9.12.28. subtitle ═══ Places the text specified by subtitle on all subsequent pages of the generated source listing. >>───#───pragma──subtitle──(──"subtitle"──)──>< You can also use the /Lu compiler option to specify the listing subtitle. Related Information o /Lu option o #pragma title o #pragma o Preprocessor Directives ═══ 9.12.29. title ═══ Places the text specified by title on all subsequent pages of the generated source listing. >>───#───pragma──title──(──"title"──)──>< You can also use the /Lt compiler option to specify the listing title. Related Information o /Lt option o #pragma subtitle o #pragma o Preprocessor Directives ═══ 9.12.30. undeclared ═══ This directive is used only by the compiler and only in template-include files. It has the syntax: >>──#──pragma──undeclared──>< In the template-include file, template functions that were explicitly declared in at least one compilation unit appear before this line. Template functions that were called, but never declared, appear after this line. For more information on template-include files, see the "Using Templates in C++ Programs" in the Programming Guide. Related Information o #pragma o Preprocessor Directives ═══ Examples of #pragma Directives ═══ The following are examples of different #pragma directives: #pragma langlvl(SAA) #pragma title("SAA pragma example") #pragma pagesize(55) #pragma map(ABC, "A$$BC@") ═══ 10. C++ Classes ═══ C++ provides a user-defined data type called a class. The C++ class is similar to the C structure data type. In C, a structure is composed of a set of data members. In C++, a class type is like a C structure, except that a class is composed of a set of data members and an optional set of operations that can be performed on the class. In C++, a class type can be declared with the keywords union, struct, or class. A union object can hold any one of a set of named members. Structure and class objects hold a complete set of members. Each class type represents a unique set of class members including data members, member functions, and other type names. The default access for members depends on the class key: o The members of a class declared with the class key class are private by default. A class is inherited privately by default. o The members of a class declared with the class key struct are public be default. A structure is inherited publicly by default. o The members of a union (declared with the class key union) are public by default. A union cannot be used as a base class in derivation. Once you create a class type, you can declare one or more objects of that class type. For example: class X { /* define class members here */ }; void main() { X xobject1; // create an object of class type X X xobject2; // create another object of class type X } This chapter introduces the concept of the class data type and discusses: o Classes and Access Control o Declaring Class Objects o Scope of Class Names Classes are also used in C++ to support polymorphic functions through overloaded functions (static compile time binding) and virtual functions (dynamic binding). C++ allows you to redefine standard operators and functions through the concept of overloading. Operator overloading facilitates data abstraction by allowing you to use classes as easily as built-in types. Related Information o C++ Class Members and Friends o Inheritance o C++ Overloading o Virtual Functions o Structures o Unions ═══ 10.1. Classes and Access Control ═══ C++ facilitates data abstraction and encapsulation by providing access control for class types. For example, if you declare private data members and public member functions, a client program can only access the private members through the public member functions and friends of that class. Such a class would have data hiding because client programs do not have access to implementation details and are forced to use a public interface to manipulate objects of the class. You can control access to class members by using access specifiers. In the following example, the class abc has three private data members a, b, and c, and three public member functions add(), mult(), and the constructor abc(). The main() function creates an object danforth of the abc class and then attempts to print the value of the member a for this object: #include class abc { private: int a, b, c; public: abc(int p1, int p2, int p3): a(p1), b(p2), c(p3) {} int add() { return a + b + c ; } int mult() { return a * b * c; } }; void main() { abc danforth(1,2,3); cout << "Here is the value of a " << danforth.a << endl; // This causes an error because a is not // a public member and thus cannot be accessed // directly } Because class members are private by default, you can omit the keyword private in the definition of abc. Because a is not a public member, the attempt to access its value directly causes an error. Related Information o Member Access o Inherited Member Access o C++ Classes ═══ 10.1.1. Declaring Classes ═══ A class-specifier is used to declare a class. Once a class specifier has been seen and its members declared, a class is considered to be defined even if the member functions of that class are not yet defined. A class specifier has the following form: >>──┬─class──┬──class-name──┬─────────────┬──{──┬─────────────┬──}────────────>< ├─struct─┤ └─:base-class─┘ └─member-list─┘ └─union──┘ The member-list is optional. It specifies the class members, both data and functions, of the class class-name. If the member-list of a class is empty, objects of that class have a nonzero size. You can use a class-name within the member-list of the class specifier itself as long as the size of the class is not required. For more information, see Class Member Lists. The base-class is optional. It specifies the base class or classes from which the class class-name inherits members. If the base-class is not empty, the class class-name is called a derived class. The declarator for a class variable declared with the class, struct, or union keyword is an identifier. If the symbol * precedes the identifier, the identifier names a pointer to a class of the specified data type. If ** precedes the identifier, the identifier names a pointer to a pointer to a class of the specified data type. If a constant expression enclosed in [ ] (brackets) follows the identifier, the identifier names an array of classes of the specified data type. If * precedes the identifier and a constant expression enclosed in [ ] follows the identifier, the identifier names an array of pointers to classes of the specified data type. You can use classes to build complicated declarators. The union type specifier can be used to declare a class declarator. Related Information o Class Names o Declaring Class Objects o Scope of Class Names o Class Member Lists o Derivation ═══ 10.1.2. Class Names ═══ A class-name is a unique identifier that becomes a reserved word within its scope. You can qualify the names of nested classes by using the :: (scope resolution) operator and the name of their enclosing class. Syntax of a Nested Class Specifier A qualified-class-specifier is an alternative way of referring to a class after it has been declared. A qualified class specifier consists of the nested class name, optionally preceded by the :: operator. Once a class name is declared, it hides other declarations of the same name within the enclosing scope. If a class name is declared in the same scope as a function, enumerator, or object with the same name, that class can be referred to by using an elaborated-type-specifier. In the following example, the elaborated type specifier is used to refer to the class print that is hidden by the later definition of the function print(): class print { /* definition of class print */ }; void print (class print*); // redefine print as a function // . // prefix class-name by class-key // . // to refer to class print // . void main () { class print* paper; // prefix class-name by class-key // to refer to class print print(paper); // call function print } You can use an elaborated type specifier with a class name to declare a class. For more information on elaborated type specifiers, see Incomplete Class Declarations. You can also qualify type names to refer to hidden type names in the current scope. You can reduce complex class name syntax by using a typedef to represent a nested class name. Example of Using a typedef for a Class Name Related Information o Declaring Classes o Declaring Class Objects o Scope of Class Names o Nested Classes ═══ Syntax of a Nested Class Specifier ═══ The syntax of a nested class specifier is: >>──class-name──┬────────────────┬────────────────────────────────────────────>< └─::nested-class─┘ where class-name specifies the name of the enclosing class and nested-class specifies the name of the nested class. For more information, see Nested Classes. ═══ Example of Using a typedef for a Class Name ═══ /************************************************************************ * In the following example, a typedef is used so that the simple name nested can be used in place of outside::middle::inside. * ************************************************************************/ #include class outside { public: class middle { public: class inside { private: int a; public: inside(int a_init = 0): a(a_init) {} void printa(); }; }; }; typedef outside::middle::inside nested; void nested::printa() { cout << "Here is a " << this->a << endl; } void main() { nested n(9); n.printa(); } ═══ 10.1.3. Classes and Structures ═══ The C++ class is an extension of the C structure. Because the only difference between a structure and a class is that a structure has public access by default and a class has private access by default, you can use the keywords class or struct to define equivalent classes. For example, in the following code fragment, the class X is equivalent to the structure Y: class X { int a; // private by default public: int f() { return a = 5; }; // public member function }; struct Y { int f() { return a = 5; }; // public by default private: int a; // private data member }; If you define a structure and then declare an object of that structure using the keyword class, the members of the object are still public by default. Example of Access for Classes and Structures An aggregate class is a class that has no constructors, no private or protected members, no base classes, and no virtual functions. Initialization of aggregate classes is described in Initializers. Related Information o Structures o Declaring Classes o Declaring Class Objects o Scope of Class Names ═══ Example of Access for Classes and Structures ═══ /************************************************************************ * In the following example, main() has access to the members of X even though X is declared as using the keyword class: * ************************************************************************/ #include struct x { int a; int b; } ; class x X; void main() { X.a = 0; X.b = 1; cout << "Here are e and f " << X.a << " " << X.b << endl; } ═══ 10.2. Declaring Class Objects ═══ A class declaration creates a unique type class name. You can use a class type to create instances or objects of that class type. For example, you can declare a class, structure, and union with class names X, Y, and Z respectively: class X { /* definition of class X */ }; struct Y { /* definition of struct Y */ }; union Z { /* definition of union Z */ }; You can then declare objects of each of these class types. Remember that classes, structures, and unions are all types of C++ classes. void main() { X xobj; // declare a class object of class type X Y yobj; // declare a struct object of class type Y Z zobj; // declare a union object of class type Z } In C++, unlike C, you do not need to precede declarations of class objects with the keywords union, struct, and class unless the name of the class is hidden. For more information on hidden names, see Scope of Class Names. When you declare more than one class object in a declaration, the declarators are treated as if declared individually. For example, if you declare two objects of class S in a single declaration: class S { /* ... */ }; void main() { S S,T; // declare two objects of class type S } this declaration is equivalent to: class S { /* ... */ }; void main() { S S; class S T; // keyword class is required // since variable S hides class type S } but is not equivalent to: class S { /* ... */ }; void main() { S S; S T; // error, S class type is hidden } You can also declare references to classes, pointers to classes, and arrays of classes. Examples of Declaring Class Objects Objects of class types that are not copy restricted can be assigned, passed as arguments to functions, and returned by functions. For more information, see Copying Class Objects. Related Information o Objects o Scope of Class Names o Initialization by Constructor o Copying Class Objects ═══ Examples of Declaring Class Objects ═══ /************************************************************************ * In C++, unlike C, you do not need to precede declarations of class objects with the keywords union, struct, and class unless the name of the class is hidden. For example: * ************************************************************************/ struct Y { /* ... */ }; class X { /* ... */ }; void main () { int X; // hides the class name X Y yobj; // valid X xobj; // error, class name X is hidden class X xobj; // valid } /************************************************************************ * The following example declares a reference, a pointer, and an array: * ************************************************************************/ class X { /* ... */ }; struct Y { /* ... */ }; union Z { /* ... */ }; void main() { X xobj; X &xref = xobj; // reference to class object of type X Y *yptr; // pointer to struct object of type Y Z zarray[10]; // array of 10 union objects of type Z } ═══ 10.3. Scope of Class Names ═══ A class declaration introduces the class name into the scope where it is declared. Any class, object, function or other declaration of that name in an enclosing scope is hidden. If a class name is declared in a scope where an object, function, or enumerator of the same name is also declared, you can only refer to the class by using the elaborated type specifier. The class key (class, struct, or union) must precede the class name to identify it. For example: class x { int a; }; // declare a class type class-name x xobject; // declare object of class type x int x(class x*) // redefine x to be a function {return 0;} // use class-key class to define // a pointer to the class type x // as the function argument void main() { class x* xptr; // use class-key class to define // a pointer to class type x xptr = &xobject; // assign pointer x(xptr); // call function x with pointer to class x } An elaborated type specifier can be used in the declaration of objects and functions. See Class Names for an example. An elaborated type specifier can also be used in the incomplete declaration of a class type to reserve the name for a class type within the current scope. Related Information o Incomplete Class Declarations o Nested Classes o Local Classes o Local Type Names o Class Names o Declaring Class Objects o Declaring Classes o Scope in C ═══ 10.3.1. Incomplete Class Declarations ═══ An incomplete class declaration is a class declaration that does not define any class members. You cannot declare any objects of the class type or refer to the members of a class until the declaration is complete. However, an incomplete declaration allows you to make specific references to a class prior to its definition as long as the size of the class is not required. For example, you can define a pointer to the structure first in the definition of the structure second. Structure first is declared in an incomplete class declaration prior to the definition of second, and the definition of oneptr in structure second does not require the size of first: struct first; // incomplete declaration of struct first struct second // complete declaration of struct second { first* oneptr; // pointer to struct first refers to // struct first prior to its complete // declaration first one; // error, you cannot declare an object of // an incompletely declared class type int x, y; }; struct first // complete declaration of struct first { second two; // define an object of class type second int z; }; If you declare a class with an empty member list, it is a complete class declaration. For example: class X; // incomplete class declaration class Z {}; // empty member list class Y { public: X yobj; // error, cannot create an object of an // incomplete class type Z zobj; // valid }; Related Information o Declaring Classes o Declaring Class Objects o Class Member Lists o Scope of Class Names ═══ 10.3.2. Nested Classes ═══ A nested class is declared within the scope of another class. The name of a nested class is local to its enclosing class. Unless you use explicit pointers, references, or object names, declarations in a nested class can only use visible constructs, including type names, static members, and enumerators from the enclosing class and global variables. Member functions of a nested class follow regular access rules and have no special access privileges to members of their enclosing classes. Member functions of the enclosing class have no special access to members of a nested class. You can define member functions and static data members of a nested class in the global scope. For example, in the following code fragment, you can access the static members x and y and member functions f() and g() of the nested class nested by using a qualified type name. Qualified type names allow you to define a typedef to represent a qualified class name. You can then use the typedef with the :: (scope resolution) operator to refer to a nested class or class member, as shown in the following example: class outside { public: class nested { public: static int x; static int y; int f(); int g(); }; }; int outside::nested::x = 5; int outside::nested::f() { return 0; }; typedef outside::nested outnest; // define a typedef int outnest::y = 10; // use typedef with :: int outnest::g() { return 0; }; // . . . Related Information o Class Names o Declaring Class Objects o Scope of Class Names ═══ 10.3.3. Local Classes ═══ A local class is declared within a function definition. The local class is in the scope of the enclosing function scope. Declarations in a local class can only use type names, enumerations, static variables from the enclosing scope, as well as external variables and functions. Examples of Local Classes Member functions of a local class have to be defined within their class definition. Member functions of a local class must be inline functions. Like all member functions, those defined within the scope of a local class do not need the keyword inline. A local class cannot have static data members. In the following example, an attempt to define a static member of a local class causes an error: void f() { class local { int f(); // error, local class has noninline // member function int g() {return 0;} // valid, inline member function static int a; // error, static is not allowed for // local class int b; // valid, nonstatic variable }; } // . . . An enclosing function has no special access to members of the local class. Related Information o Scope of Class Names o Function Scope o Inline Member Functions o Inline Specifiers o Local Type Names ═══ Examples of Local Classes ═══ /************************************************************************ * The following example uses local classes. * ************************************************************************/ int x; // global variable void f() // function definition { static int y; // static variable y can be used by // local class int x; // auto variable x cannot be used by // local class extern int g(); // extern function g can be used by // local class class local // local class { int g() { return x; } // error, local variable x // cannot be used by g int h() { return y; } // valid,static variable y int k() { return ::x; } // valid, global x int l() { return g(); } // valid, extern function g }; } void main() { local* z; // error, local is undefined // . // . // . } ═══ 10.3.4. Local Type Names ═══ Local type names follow the same scope rules as other names. Scope rules are described in Scope in C++. Type names defined within a class declaration have local scope and cannot be used outside their class without qualification. If you use a class name, typedef name, or a constant name that is used in a type name, in a class declaration, you cannot redefine that name after it is used in the class declaration. For example: void main () { typedef double db; struct st { db x; typedef int db; // error db y; }; } The following declarations are valid: typedef float T; class s { typedef int T; void f(const T); }; Here, function f() takes an argument of type s::T. However, the following declarations, where the order of the members of s has been reversed, cause an error: typedef float T; class s { void f(const T); typedef int T; }; In a class declaration, you cannot redefine a name that is not a class name, or a typedef name to a class name or typedef name once you have used that name in the class declaration. Related Information o Scope in C o Declaring Classes o Declaring Class Objects o Scope of Class Names o Local Classes o typedef ═══ 11. C++ Class Members and Friends ═══ This chapter describes class members and friends, including the following topics: o Class Member Lists o Data Members o Class-Type Class Members o Member Bit Fields o Member Functions o Member Scope o Pointers to Members o The this Pointer o Static Members o Member Access o Friends Related Information o C++ Classes o Inheritance o Special Member Functions ═══ 11.1. Class Member Lists ═══ An optional member list declares objects called class members. Class members can be data, functions, classes, enumeration, bit fields, and type names. A member list is the only place you can declare class members. Friend declarations are not class members but must appear in member lists. The member list follows the class name and is placed between braces. It can contain access specifiers, member declarations, and member definitions. You can access members by using the class access . (dot) and -> (arrow) operators. An access specifier is one of public, private, or protected. A member declaration declares a class member for the class containing the declaration. For more information on declarations, see Declarations and Definitions, and Declaring Class Objects. A member declaration that is a qualified name followed by a ; (semicolon) is used to restore access to members of base classes and is described in Access Declarations. A member declarator declares an object, function, or type within a declaration. It cannot contain an initializer. You can initialize a member by using a constructor or, if the member belongs to an aggregate class, by using a brace initializer list (a list surrounded by braces { }) in the declarator list. You must explicitly initialize a class containing constant or reference members with a brace initializer list or explicitly with a constructor. A member declarator of the form: [identifier] : constant-expression specifies a bit field. A pure specifier (= 0) indicates that a function has no definition. A pure specifier is only used with virtual member functions. A pure specifier replaces the function definition of a member function in the member list. You can use the storage-class specifier static (but not extern, auto or register) in a member list. The order of mapping of class members in a member list is implementation dependent. For the C/C++ Tools compiler, class members are allocated in the order they are declared. For more information, see the IBM C/C++ Tools: Programming Guide. Related Information o Member Access o Dot Operator o Arrow Operator o Declaring Class Objects o Initializers o Access Declarations o Initialization by Constructor o Virtual Functions o Storage Class Specifiers ═══ 11.2. Data Members ═══ Data members include members that are declared with any of the fundamental types, as well as other types, including pointer, reference, array types, and user-defined types. You can declare a data member the same way as a variable, except that explicit initializers are not allowed inside the class definition. If an array is declared as a nonstatic class member, you must specify all of the dimensions of the array. Related Information o Types o Class Member Lists o Class-Type Class Members o Member Bit Fields o Static Members o Member Access ═══ 11.3. Class-Type Class Members ═══ A class can have members that are of a class type or are pointers or references to a class type. Members that are of a class type must be of a class type that is previously declared. An incomplete class type can be used in a member declaration as long as the size of the class is not needed. For example, a member can be declared that is a pointer to an incomplete class type. A class X cannot have a member that is of type X, but it can contain pointers to X, references to X, and static objects of X. Member functions of X can take arguments of type X and have a return type of X. For example: class X { X(); X *xptr; X &xref; static X xcount; X xfunc(X); }; The bodies of member functions are always processed after the definition of their class is complete. The body of a member function can use the enclosing class. Consider the following example: class Y { public: int a; Y (); private: int f() {return sizeof(Y);}; void g(Y yobj); Y h(int a); }; In this example, the inline function f() uses the size of class Y. Related Information o Incomplete Class Declarations o Member Functions o Inline Member Functions o C++ Classes o Class Member Lists ═══ 11.4. Member Bit Fields ═══ A class can contain packed data known as bit fields. You can use bit fields for data that requires just a few bits of storage. The syntax for a bit field is: [identifier] : constant-expression The constant expression specifies how many bits the field reserves. A bit field that is defined as having a length of zero causes the next field to be aligned on the next integer boundary. Bit fields with a length of zero must be unnamed. Unlike ANSI C, bit fields can be any integral type or enumeration type. When you assign a value that is out of range to a bit field, the low-order bit pattern is preserved and the appropriate bits are assigned. The following restrictions apply to member bit fields. You cannot: o Have a reference to a bit field o Define an array of bit fields o Take the address of a bit field The maximum bit field length is implementation dependent. For the C/C++ Tools compiler, it is 32 bits. For more information, see the IBM C/C++ Tools: Programming Guide. Related Information o Class Member Lists ═══ 11.5. Member Functions ═══ Member functions are operators and functions that are declared as members of a class. Member functions do not include operators and functions declared with the friend specifier. These are called friends of a class. The definition of a member function is within the scope of its enclosing class. The body of a member function is analyzed after the class declaration so that members of that class can be used in the member function body. When the function add() is called in the following example, the data variables a, b, and c can be used in the body of add(). class x { public: int add() // inline member function add {return a+b+c;}; private: int a,b,c; }; There are a number of types of member functions: o const and volatile member functions o Virtual member functions o Special member functions o Inline member functions o Member function templates Related Information o Member Scope o Static Member Functions o Functions o Class Member Lists ═══ const and volatile Member Functions ═══ A member function declared with the const qualifier can be called for constant and nonconstant objects. A nonconstant member function can only be called for a nonconstant object. Similarly, a member function declared with the volatile qualifier can be called for volatile and nonvolatile objects. A nonvolatile member function can only be called for a nonvolatile object. ═══ Virtual Member Functions ═══ Virtual member functions are declared with the keyword virtual. They allow dynamic binding of member functions. Because all virtual functions must be member functions, virtual member functions are simply called virtual functions. If the definition of a virtual function is replaced by a pure specifier in the declaration of the function, the function is said to be declared pure. A class that has at least one pure virtual function is called an abstract class. ═══ Special Member Functions ═══ Special member functions are used to create, destroy, initialize, convert, and copy class objects. These include: o Constructors o Destructors o Conversion constructors o Conversion functions o Copy constructors ═══ Inline Member Functions ═══ A member function that is both declared and defined in the class member list is called an inline member function. Member functions containing a few lines of code are usually declared inline. An equivalent way to declare an inline member function is to declare it outside of the class declaration using the keyword inline and the :: (scope resolution) operator to identify the class the member function belongs to. For example: class Y { char* a; public: char* f() {return a;}; }; is equivalent to: class Z { char* a; public: char* f(); }; inline char* Z::f() {return a;} When you declare an inline function without the inline keyword and do not define it in the class member list, you cannot call the function before you define it. In the above example you could not call f() until after its definition. Inline member functions have internal linkage. Noninline member functions have external linkage. For more information, see Inline Functions. ═══ Member Function Templates ═══ Any member function (inlined or noninlined) declared within a class template is implicitly a function template. When a template class is declared, it implicitly generates template functions for each function defined in the class template. For more information, see Member Function Templates. ═══ 11.6. Member Scope ═══ Member functions and static members can be defined outside their class declaration if they have already been declared, but not defined, in the class member list. Nonstatic data members are defined when their class is instantiated. The declaration of a static data member is not a definition. The declaration of a member function is a definition if the body of the function is also given. Whenever the definition of a class member appears outside of the class declaration, the member name must be qualified by the class name using the :: (scope resolution) operator. Example of Defining a Member outside of the Class All member functions are in class scope even if they are defined outside their class declaration. The name of a class member is local to its class. Unless you use one of the class access operators, . (dot), or -> (arrow), or :: (scope resolution) operator, you can only use a class member in a member function of its class and in nested classes. You can only use types, enumerations and static members in a nested class without qualification with the :: operator. The order of search for a name in a member function body is: 1. Within the member function body itself 2. Within all the enclosing classes, including inherited members of those classes 3. Within the lexical scope of the body declaration Example of Member Function Search Path Note: When the containing classes are being searched, only the definitions of the containing classes and their base classes are searched. The scope containing the base class definitions (global scope, in this example) is not searched. Related Information o Scope in C++ o Scope Resolution Operator o Member Functions o Dot Operator o Arrow Operator o Member Access ═══ Example of Defining a Member ═══ /************************************************************************ * The following example defines a member function outside of its class declaration. * ************************************************************************/ #include class X { public: int a, b ; // public data members int add(); // member function declaration only }; int a = 10; // global variable // define member function outside its class declaration int X::add() {return a + b;}; // . // . // . void main() { int answer; X xobject; xobject.a = 1; xobject.b = 2; answer = xobject.add(); cout << xobject.a << " + " << xobject.b << " = " << answer; } /************************************************************************ * The output for this example is: 1 + 2 = 3 Note: All member functions are in class scope even if they are defined outside their class declaration. In the above example, the member function add() returns the data member a, not the global variable a. * ************************************************************************/ ═══ Example of Member Function Search Path ═══ /************************************************************************ * The search of the enclosing classes, including inherited members, is demonstrated in the following example: * ************************************************************************/ class A { /* ... */ }; class B { /* ... */ }; class C { /* ... */ }; class Z : A { class Y : B { class X : C { int f(); /* ... */ }; }; }; int Z::Y::X f() { // ... j(); // ... } /************************************************************************ * In this example, the search for the name j in the definition of the function f follows this order: 1. In the body of the function f 2. In X and in its base class C 3. In Y and in its base class B 4. In Z and in its base class A 5. In the lexical scope of the body of f. In this case, this is global scope. * ************************************************************************/ ═══ 11.7. Pointers to Members ═══ Pointers to members allow you to refer to nonstatic members of class objects. You cannot use a pointer to member to point to a static class member because the address of a static member is not associated with any particular object. To point to a static class member, you must use a normal pointer. You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions. Note that a member function does not have the same type as a nonmember function that has the same number and type of arguments and the same return type. Example of Pointers to Members To reduce complex syntax, you can declare a typedef to be a pointer to a member. A pointer to a member can be declared and used as shown in the following code fragment: typedef void (X::*ptfptr) (int); // declare typedef void main () { // ... ptfptr ptf = &X::f; // use typedef X xobject; (xobject.*ptf) (20); // call function } The pointer to member operators .* and ->* are used to bind a pointer to a member of a specific class object. Because the precedence of () (function call operator) is higher than .* and ->*, you must use parentheses to call the function pointed to by ptf. Related Information o Pointer to Member Operators .* ->* o Pointers o Static Members o The this Pointer ═══ Example of Pointers to Members ═══ /************************************************************************ * Pointers to members can be declared and used as shown in the following example: * ************************************************************************/ #include class X { public: int a; void f(int b) { cout << "The value of b is "<< b << endl; } }; // . // . // . void main () { // declare pointer to data member int X::*ptiptr = &X::a; // declare a pointer to member function void (X::* ptfptr) (int) = &X::f; X xobject; // create an object of class type X xobject.*ptiptr = 10; // initialize data member cout << "The value of a is " << xobject.*ptiptr << endl; (xobject.*ptfptr) (20); // call member function } /************************************************************************ * The output for this example is: The value of a is 10 The value of b is 20 * ************************************************************************/ ═══ 11.8. The this Pointer ═══ The keyword this identifies a special type of pointer. When a nonstatic member function is called, the this pointer identifies the class object which the member function is operating on. You cannot declare the this pointer or make assignments to it. The type of the this pointer for a member function of a class type X, is X* const. If the member function is declared with the constant qualifier, the type of the this pointer for that member function for class X, is const X* const. If the member function is declared with the volatile qualifier, the type of the this pointer for that member function for class X is volatile X* const. this is passed as a hidden argument to all nonstatic member function calls and is available as a local variable within the body of all nonstatic functions. For example, you can refer to the particular class object that a member function is called for by using the this pointer in the body of the member function. The following code example produces the output a = 5: #include class X { int a; public: // The 'this' pointer is used to retrieve 'xobj.a' hidden by // the automatic variable 'a' void Set_a(int a) { this->a = a; } void Print_a() { cout << "a = " << a << endl; } }; void main() { X xobj; int a = 5; xobj.Set_a(a); xobj.Print_a(); } Unless a class member name is hidden, using the class member name is equivalent to using the class member name qualified with the this pointer. Example of the this Pointer Related Information o Pointers o Member Functions o Pointers to Members o C++ Classes ═══ Example of the this Pointer ═══ /************************************************************************ * The following example shows code using class members without the this pointer. The comments on each line show the equivalent code with the hidden use of the this pointer. * ************************************************************************/ #include #include class X { int len; char *ptr; public: int GetLen() // int GetLen (X* const this) { return len; } // { return this->len; } char * GetPtr() // char * GetPtr (X* const this) { return ptr; } // { return this->ptr; } X& Set(char *); X& Cat(char *); X& Copy(X&); void Print(); }; X& X::Set(char *pc) // X& X::Set(X* const this, char *pc) { len = strlen(pc); // this->len = strlen(pc); ptr = new char[len]; // this->ptr = // new char[this->len]; strcpy(ptr, pc); // strcpy(this->ptr, pc); return *this; } X& X::Cat(char *pc) // X& X::Cat(X* const this, char *pc) { len += strlen(pc); // this->len += strlen(pc); strcat(ptr,pc); // strcat(this->ptr,pc); return *this; } X& X::Copy(X& x) // X& X::Copy(X* const this, X& x) { Set(x.GetPtr()); // this->Set(x.GetPtr(&x)); return *this; } void X::Print() // void X::Print(X* const this) { cout << ptr << endl; // cout << this->ptr << endl; } void main() { X xobj1; xobj1.Set("abcd").Cat("efgh"); // xobj1.Set(&xobj1, "abcd").Cat(&xobj1, "efgh"); xobj1.Print(); // xobj1.Print(&xobj1); X xobj2; xobj2.Copy(xobj1).Cat("ijkl"); // xobj2.Copy(&xobj2, xobj1).Cat(&xobj2, "ijkl"); xobj2.Print(); // xobj2.Print(&xobj2); } /************************************************************************ * The above example produces the following output: abcdefgh abcdefghijkl * ************************************************************************/ ═══ 11.9. Static Members ═══ Class members can be declared using the storage-class specifier static in the class member list. There is only one copy of the static member that is shared by all objects of a class in a program. When you declare an object of a class having a static member, the static member is not part of the class object. A typical use of static members is for recording data common to all objects of a class. For example, you can use a static data member as a counter to store the number of objects of a particular class type that are created. Each time a new object is created, this static data member can be incremented to keep track of the total number of objects. The declaration of a static member in the member list of a class is not a definition. The definition of a static member is equivalent to an external variable definition. You must define the static member outside of the class declaration. For example: class X { public: static int i; } int X::i = 0; // definition outside class declaration // . // . // . A static member can be accessed from outside of its class only if it is declared with the keyword public. You can then access the static member by qualifying the class name using the :: (scope resolution) operator. In the following example: class X { public: static int f(); }; void main () { X::f(); } you can refer to the static member f() of class type X as X::f(). Related Information o static Storage Class Specifier o Using the Class Access Operators with Static Members o Static Data Members o Static Member Functions ═══ 11.9.1. Using the Class Access Operators with Static Members ═══ You can also access a static member from a class object by using the class access operators . (dot) and -> (arrow). When a static member is accessed through a class access operator, the expression on the left of the . or -> operator is not evaluated. Example of Accessing Static Members A static member can be referred to independently of any association with a class object because there is only one static member shared by all objects of a class. A static member can exist even if no objects of its class have been declared. When you access a static member, the expression that you use to access it is not evaluated. In the following example, the external function f() returns class type X. The function f() can be used to access the static member i of class X. The function f() itself is not called. class X { public: static int i; }; int X::i = 10; X f() { /* ... */ } void main () { int a; a = f().i; // f().i does not call f() } Related Information o Static Members o Dot Operator o Arrow Operator o Static Data Members o Static Member Functions ═══ Example of Accessing Static Members ═══ /************************************************************************ * The following example uses the class access operators to access static members. * ************************************************************************/ #include class X { static int cnt; public: // The following routines all set X's static variable cnt // and print its value. void Set_Show (int i) { X::cnt = i; cout << "X::cnt = " << X::cnt << endl; } void Set_Show (int i, int j ) { this->cnt = i+j; cout << "X::cnt = " << X::cnt << endl; } void Set_Show (X& x, int i) { x.cnt = i; cout << "X::cnt = " << X::cnt << endl; } }; int X::cnt; void main() { X xobj1, xobj2; xobj1.Set_Show(11); xobj1.Set_Show(11,22); xobj1.Set_Show(xobj2, 44); } /************************************************************************ * The above example produces the following output: X::cnt = 11 X::cnt = 33 X::cnt = 44 * ************************************************************************/ ═══ 11.9.2. Static Data Members ═══ Static data members of global classes have external linkage and can be initialized in file scope like other global objects. Static data members follow the usual class access rules, except that they can be initialized in file scope. Static data members and their initializers can access other static private and protected members of their class. The initializer for a static data member is in the scope of the class declaring the member. The following example shows how you can initialize static members using other static members, even though these members are private: class C { static int i; static int j; static int k; static int l; static int m; static int n; static int p; static int q; static int r; static int f() { return 0; } int a; C() { a = 0; } }; C c; int C::i = C::f(); // initialize with static member function int C::j = C::i; // initialize with another static data member int C::k = c.f(); // initialize with member function from an object int C::l = c.j; // initialize with data member from an object int C::s = c.a; // initialize with nonstatic data member int C::r = 1; // initialize with a constant value class Y : private C {} y; int C::m = Y::f(); int C::n = Y::r; int C::p = y.r; // error int C::q = y.f(); // error The initializations of C::p and C::q cause errors because y is an object of a class that is derived privately from C, and thus its members are not accessible to members of C. You can only have one definition of a static member in a program. If a static data member is not initialized, it is assigned a zero default value. Local classes cannot have static data members. Example of Static Data Members Related Information o Static Member Functions o Static Members o Using the Class Access Operators with Static Members o External Linkage o Member Access o Local Classes ═══ Example of Static Data Members ═══ /************************************************************************ * The following example shows the declaration, initialization, use, and scope of the static data member si and static member functions Set_si(int) and Print_si(). * ************************************************************************/ #include class X { int i; static int si; public: void Set_i(int i) { this->i = i; } void Print_i() { cout << "i = " << i << endl; } // Equivalent to: // void Print_i(X* this) // { cout << "X::i = " << this->i << endl; } static void Set_si(int si) { X::si = si; } static void Print_si() { cout << "X::si = " << X::si << endl; } // Print_si doesn't have a 'this' pointer }; int X::si = 77; // Initialize static data member void main() { X xobj; // Non-static data members and functions belong to specific // instances (here xobj) of class X xobj.Set_i(11); xobj.Print_i(); // static data members and functions belong to the class and // can be accessed without using an instance of class X X::Print_si(); X::Set_si(22); X::Print_si(); } /************************************************************************ * The above example produces the following output: i = 11 X::si = 77 X::si = 22 * ************************************************************************/ ═══ 11.9.3. Static Member Functions ═══ You cannot have static and nonstatic member functions with the same names and the same number and type of arguments. A static member function does not have a this pointer. You can call a static member function using the this pointer of a nonstatic member function. In the following example, the nonstatic member function printall() calls the static member function f() using the this pointer: #include class c { static void f() { cout << "Here is i" << i << endl;&rbr c. static int i; int j; public: c(int firstj): j(firstj) {} void printall(); }; void c::printall() { cout << "Here is j " << this->j << endl; this->f(); } int c::i = 3; void main() { class c C(0); C.printall(); } A static member function cannot be declared with the keyword virtual. A static member function can access only the names of static members, enumerators, and nested types of the class in which it is declared. Related Information o Member Functions o Using the Class Access Operators with Static Members o Static Data Members o Static Members o The this Pointer o Virtual Functions ═══ 11.10. Member Access ═══ Member access determines if a class member is accessible in an expression or declaration. Note that accessibility and visibility are independent. Visibility is based on the scoping rules of C++. A class member can be visible and inaccessible at the same time. This section describes how you control the access to the individual nonderived class members by using access specifiers when you declare class members in a member list. The access specifiers are: public, private, and protected. The three access specifiers have the following effect: o public class members can be accessed by any function, file or class. o private class members can be accessed only by member functions and friends of the class in which the member is declared. o protected class members can be accessed only by member functions and friends of the class in which they are declared and by member functions and friends of classes derived from the class in which the protected members are declared. The access specifier protected can be used for nonbase class members, but it is equivalent to private unless it is used in a base class member declaration or in a base list. The default access for an individual class member depends on the class key used in the class declaration. Members of classes declared with the keyword class are private by default. Members of classes declared with the keyword struct or union are public by default. The access specifier protected is meaningful only in the context of derivation. You can control the access to inherited members (that is, base class members) by including access specifiers in the base list of the derived class declaration. You can also restore the access to an inherited member from a derived class by using an access declaration. Access for inherited members is described in Inherited Member Access. Member lists can include access specifiers as labels. Members declared after these labels have access as specified by the label they follow. An access specifier determines the access for members until another access specifier is used or until the end of the class declaration. You can use any number of access specifiers in any order. Examples of Access Specifiers Related Information o Access Declarations o Inherited Member Access o Class Member Lists o Inherited Member Access ═══ Examples of Access Specifiers ═══ /************************************************************************ * The following example shows access specifiers in member lists. * ************************************************************************/ class X { int a; // private data by default public: void f(int); // public function int b; // public data private: int c; // private data protected: void g(int); // protected function }; struct Y { int a; // public data by default public: int b; // public data private: void g(int); // private function int c; // private data }; ═══ 11.11. Friends ═══ A friend of a class X is a function or class that is granted the same access to X as the members of X. Functions declared with the friend specifier in a class member list are called friend functions of that class. Classes declared with the friend specifier in the member list of another class are called friend classes of that class. A class Y must be defined before any member of Y can be declared a friend of another class. You can declare an entire class as a friend. If the class has not been previously declared, use an elaborated type specifier and a qualified type specifier to specify the class name. If the friend class has been previously declared, you can omit the keyword class, as shown in the following example: class F; class X { public: X() {a=1; b=2;} private: int a, b; friend F; // elaborated-type-specifier not required }; Examples of Friends Related Information o Friend Scope o Friend Access o C++ Classes o Member Functions ═══ Example of a friend Function ═══ /************************************************************************ * In the following example, the friend function print is a member of class Y and accesses the private data members a and b of class X. * ************************************************************************/ #include class X; class Y { public: void print(X& x); }; class X { public: X() {a=1; b=2;} private: int a, b; friend void Y::print(X& x); }; void Y::print(X& x) { cout << "A is "<< x.a << endl; cout << "B is " << x.b << endl; } void main () { X xobj; Y yobj; yobj.print(xobj); } /************************************************************************ * In the following example, the friend class F has a member function print that accesses the private data members a and b of class X and performs the same task as the friend function print in the above example. Any other members declared in class F also have access to all members of class X. In the following example, the friend class F has not been previously declared, so an elaborated type specifier and a qualified type specifier are used to specify the class name. * ************************************************************************/ #include class X { public: X() {a=1; b=2;} // constructor private: int a, b; friend class F; // friend class }; class F { public: void print(X& x) { cout << "A is " << x.a << endl; cout << "B is " << x.b << endl; } }; void main () { X xobj; F fobj; fobj.print(xobj); } /************************************************************************ * Both the above examples produce the following output: A is 1 B is 2 * ************************************************************************/ ═══ 11.11.1. Friend Scope ═══ The name of a friend function or class first introduced in a friend declaration is not in the scope of the class granting friendship (also called the enclosing class) and is not a member of the class granting friendship. The name of a function first introduced in a friend declaration is in the scope of the first nonclass scope that contains the enclosing class. The body of a function provided in a friend declaration is handled in the same way as a member function defined within a class. Processing of the definition does not start until the end of the outermost enclosing class. In addition, unqualified names in the body of the function definition are searched for starting from the class containing the function definition. A class that is first declared in a friend declaration is equivalent to an extern declaration. For example: class B {}; class A { friend class B; // global class B is a friend of A }; If the name of a friend class has been introduced before the friend declaration, the compiler searches for a class name that matches the name of the friend class beginning at the scope of the friend declaration. If the declaration of a nested class is followed by the declaration of a friend class with the same name, the nested class is a friend of the enclosing class. The scope of a friend class name is the first nonclass enclosing scope. For example: class A { class B { // arbitrary nested class definitions friend class C; }; }; is equivalent to: class C; class A { class B { // arbitrary nested class definitions friend class C; }; }; You need to use the class member access operators if the friend function is a member of another class. For example: class A { public: int f() { /* ... */ } }; class B { friend int A::f(); }; Friends of a base class are not inherited by any classes derived from that base class. Related Information o Scope of Class Names o Friend Access o Friends o Nested Classes o Derivation ═══ 11.11.2. Friend Access ═══ A friend of a class can access the private and protected members of that class. Normally, you can only access the private members of a class through member functions of that class, and you can only access the protected members of a class through member functions of a class or classes derived from that class. Friend declarations are not affected by access specifiers. Related Information o Member Access o Friend Scope o Friends ═══ 12. C++ Overloading ═══ Overloading enables you to redefine functions and most standard C++ operators. Typically, you overload a function or operator if you want to extend the operations the function or operator performs to different data types. This section discusses: o Overloading Functions o Argument Matching o Overloading Operators o Overloading Unary Operators o Overloading Binary Operators o Special Overloaded Operators Related Information o Functions o Expressions and Operators ═══ 12.1. Overloading Functions ═══ You can overload a function by having multiple declarations of the same function name in the same scope. The declarations differ in the type and number of arguments in the argument list. When an overloaded function is called, the correct function is selected by comparing the types of the actual arguments with the types of the formal arguments. Consider a function print, which displays an int. You can overload the function print to display other types, for example, double and char*. You can have three functions with the same name, each performing a similar operation on a different data type. #include void print(int i) { cout << " Here is int " << i << endl; } void print(double f) { cout << " Here is float " << f << endl; } void print(char* c) { cout << " Here is char* " << c << endl; } void main() { print(10); // calls print(int) print(10.10); // calls print(double) print("ten"); // calls print(char*) } Two function declarations are identical if all of the following are true: o They have the same function name o They are declared in the same scope o They have identical argument lists When you declare a function name more than once in the same scope, the second declaration of the function name is interpreted by the compiler as follows: o If the return type, argument types, and number of arguments of the two declarations are identical, the second declaration is considered a declaration of the same function as the first. o If only the return types of the two function declarations differ, the second declaration is an error. o If either the argument types or number of arguments of the two declarations differ, the function is considered to be overloaded. Restrictions on Overloaded Functions Related Information o Functions o Function Declarations o Scope in C++ o Argument Matching o Member Functions o Inheritance ═══ 12.1.1. Restrictions on Overloaded Functions ═══ o Functions that differ only in return type cannot have the same name. o Two member functions that differ only in that one is declared with the keyword static and the other is not cannot have the same name. o A typedef is a synonym for another type, not a separate type. Thus, the following two declarations of spadina() are declarations of the same function: typedef int I; void spadina(float, int); void spadina(float, I); o A member function of a derived class is not in the same scope as a member function in a base class with the same name. A derived class member hides a base class member with the same name. o Arguments type that differ only in that one is a pointer * and the other is an array [ ] are identical. The following two declarations are equivalent: f(char*); f(char[10]); ═══ 12.2. Argument Matching ═══ When an overloaded function or overloaded operator is called, the compiler chooses the function declaration with the best match on all arguments from all the function declarations that are visible. The compiler compares the actual arguments of a function call with the formal arguments of all declarations of the function that are visible. For a best match to occur, the compiler must be able to distinguish a function that: o Has at least as good a match on all arguments as any other function with the same name o Has at least one better argument match than any other function with the same name If no such function exists, the call is not allowed. There are three possible outcomes of a call to an overloaded function. The compiler can find: o An exact match o No match o An ambiguous match An ambiguous match occurs when the actual arguments of the function call match more than one overloaded function. Argument matching can include performing standard and user-defined conversions on the arguments to match the actual arguments with the formal arguments. Only a single user-defined conversion is performed in a sequence of conversions on an actual argument. In addition, the best-matching sequence of standard conversions is performed on an actual argument. The best-matching sequence is the shortest sequence of conversions between two standard types. For example, the conversion: int -> float -> double can be shortened to the best-matching conversion sequence: int -> double because the conversion from int to double is allowed. Trivial Conversions do not affect the choice of conversion sequence. Conversion sequences are described in Sequences of Conversions. Related Information o Sequences of Conversions o Trivial Conversions o Overloading Functions o Overloading Operators ═══ 12.2.1. Sequences of Conversions ═══ Argument-matching conversions occur in the following order: 1. An exact match in which the actual arguments match exactly (including a match with one or more trivial conversions) with the type and number of formal arguments of one declaration of the overloaded function 2. A match with promotions in which a match is found when one or more of the actual arguments is promoted 3. A match with standard conversions in which a match is found when one or more of the actual arguments is converted by a standard conversion 4. A match with user-defined conversions in which a match is found when one or more of the actual arguments is converted by a user-defined conversion 5. A match with ellipses Match through promotions follows the rules for Type Conversions. You can override an exact match by using an explicit cast. In the following example, the second call to f() matches with f(void*): void f(int); void f(void*); void main() { f(0xaabb); // matches f(int); f((void*) 0xaabb); // matches f(void*) } The implicit first argument for a nonstatic member function or operator is the this pointer. It refers to the class object for which the member function is called. When you overload a nonstatic member function, the first implicit argument, the this pointer, is matched with the object or pointer used in the call to the member function. User-defined conversions are not applied in this type of argument matching for overloaded functions or operators. When you call an overloaded member function of class X using the . (dot) or -> (arrow) operator, the this pointer has type X* const. The type of the this pointer for a constant object is const X* const. The type of the this pointer for a volatile object is volatile X* const. Related Information o Argument Matching o Trivial Conversions o Type Conversions o User-Defined Conversions o The this Pointer o Overloading Functions o Overloading Operators o Dot Operator o Arrow Operator ═══ 12.2.2. Trivial Conversions ═══ Functions cannot be distinguished if they have the same name and have arguments that differ only in that one is declared as a reference to a type and the other is that type. Thus, you cannot have two functions with the same name and with arguments differing only in this respect. The following two declarations cannot be distinguished, and thus the second one causes an error: double f(double i); // declaration double f(double &i); // error However, functions with the same name having arguments that differ only in that one is a pointer or reference and the other is a pointer to const or const reference can be distinguished. Functions with the same name having arguments that differ only in that one is a pointer or reference and the other is a pointer to volatile or volatile reference can also be distinguished. For the purpose of finding a best match of arguments, functions that have a volatile or const match (not requiring a trivial conversion) are better than those that have a volatile or const mismatch. Related Information o Argument Matching o Sequences of Conversions o Type Conversions o User-Defined Conversions o Overloading Functions o Overloading Operators ═══ 12.3. Overloading Operators ═══ You can overload one of the standard C++ operators by redefining it to perform a particular operation when it is applied to an object of a particular class. Overloaded operators must have at least one argument that has class type. An overloaded operator is called an operator function and is declared with the keyword operator preceding the operator. Overloaded operators are distinct from overloaded functions, but, like overloaded functions, they are distinguished by the number and types of operands used with the operator. You can overload any of the following operators: + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= && || ++ -- , ->* -> () [] new delete where () is the function call operator and [] is the subscript operator. Consider the standard + (plus) operator. When this operator is used with operands of different standard types, the operators have slightly different meanings. For example, the addition of two integers is not implemented in the same way as the addition of two floating-point numbers. C++ allows you to define your own meanings for the standard C++ operators when they are applied to class types. Example of an Overloaded Operator The argument-matching conventions and rules described in Argument Matching apply to overloaded operators. You can overload both the unary and binary forms of: + - * & When an overloaded operator is a member function, the first operand is matched against the class type of the overloaded operator. The second operand, if one exists, is matched against the argument in the overloaded operator call. When an overloaded operator is a nonmember function, at least one operand must have class or enumeration type. The first operand is matched against the first argument in the overloaded operator call. The second operand, if one exists, is matched against the second argument in the overloaded operator call. An overloaded operator must be either a member function, as shown in the following example: class X { public: X operator!(); X& operator =(X&); X operator+(X&); }; X X::operator!() { /* ... */ } X& X::operator=(X& x) { /* ... */ } X X::operator+(X& x) { /* ... */ } or take at least one argument of class, a reference to a class, an enumeration, or a reference to an enumeration, as shown below: class Y; { // . }; class Z; { // . }; Y operator!(Y& y); Z operator+(Z& z, int); Usually, overloaded operators are invoked using the normal operator syntax. You can also call overloaded operators explicitly by qualifying the operator name. Restrictions on Overloaded Operators Related Information o Overloading Unary Operators o Overloading Binary Operators o Special Overloaded Operators o Argument Matching o Overloading Functions o Expressions and Operators ═══ Example of an Overloaded Operator ═══ /************************************************************************ * In the following example, a class called complx is defined to model complex numbers, and the + (plus) operator is redefined in this class to add two complex numbers. * ************************************************************************/ #include class complx { double real, imag; public: complx( double real = 0., double imag = 0.); // constructor complx operator+(const complx&) const; // operator+() }; // define constructor complx::complx( double r, double i ) { real = r; imag = i; } // define overloaded + (plus) operator complx complx::operator+ (const complx& c) const { complx result; result.real = (this->real + c.real); result.imag = (this->imag + c.imag); return result; } void main() { complx x(4,4); complx y(6,6); complx z = x + y; // calls complx::operator+() } /************************************************************************ * For the class complx, described above, you can call the overloaded + (plus) operator either implicitly or explicitly as shown below. * ************************************************************************/ class complx { double real, imag; public: complx( double real = 0., double imag = 0.); complx operator+(const complx&) const; }; // . // . // . void main() { complx x(4,4); complx y(6,6); complx u = x.operator+(y); // explicit call complx z = x + y; // implicit call to complx::operator+() } ═══ 12.3.1. Restrictions on Overloaded Operators ═══ o The following C++ operators cannot be overloaded: . .* :: ?: o You cannot overload the preprocessing symbols # and ##. o You cannot change the precedence, grouping, or number of operands of the standard C++ operators. For more information, see Operator Precedence. o An overloaded operator (except for the function call operator) cannot have default arguments or an ellipsis in the argument list. o You must declare the overloaded =, [], () and -> operators as nonstatic member functions to ensure that they receive lvalues as their first operands. o The operators new and delete do not follow the general rules described in this section. new and delete are described on page Overloaded new and delete. o All operators except the = operator are inherited. Copy by Assignment describes the behavior of the assignment operator. o Unless they are explicitly mentioned in Special Overloaded Operators, overloaded unary and binary operators follow the rules outlined in Overloading Unary Operators and Overloading Binary Operators. For more information on standard C++ operators, see Expressions and Operators. ═══ 12.3.2. Overloading Unary Operators ═══ You can overload a prefix unary operator by declaring a nonmember function taking one argument or a nonstatic member function taking no arguments. When you prefix a class object with an overloaded unary operator, for example: class X { // ... }; void main () { X x; !x; // overloaded unary operator } the operator function call !x can be interpreted as: x.operator!() or operator!(x) . depending on the declarations of the operator function. If both forms of the operator function have been declared, argument matching determines which interpretation is used. Related Information o Overloading Binary Operators o Overloading Operators o Special Overloaded Operators o Restrictions on Overloaded Operators o Unary Expression ═══ 12.3.3. Overloading Binary Operators ═══ You can overload a binary operator by declaring a nonmember function taking two arguments or a nonstatic member function taking one argument. When you use a class object with an overloaded binary operator, for example: class X { // ... }; void main () { X x; int y=10; x*y; // overloaded binary operator } the operator function call x*y can be interpreted as: x.operator*(y) or operator*(x,y) depending on the declarations of the operator function. If both forms of the operator function have been declared, argument matching determines which interpretation is used. Related Information o Overloading Unary Operators o Overloading Operators o Special Overloaded Operators o Restrictions on Overloaded Operators o Binary Expression ═══ 12.4. Special Overloaded Operators ═══ The following overloaded operators do not fully follow the rules for unary or binary overloaded operators: o Assignment o Function Call o Subscripting o Class Member Access o Increment and Decrement o new and delete Related Information o Overloading Unary Operators o Overloading Binary Operators o Overloading Operators o Restrictions on Overloaded Operators o Member Functions ═══ 12.4.1. Overloaded Assignment ═══ You can only overload an assignment operator by declaring a nonstatic member function. The following example shows how you can overload the assignment operator for a particular class: class X { public: X(); X& operator=(X&); X& operator=(int); }; X& X::operator=(X& x) { /* ... */ } X& X::operator=(int i) { /* ... */ } void main() { X x1, x2; x1 = x2; // call x1.operator=(x2) x1 = 5; // call x1.operator=(5) } You cannot declare an overloaded assignment operator that is a nonmember function. Overloaded assignment operators are not inherited. If a copy assignment operator function is not defined for a class, the copy assignment operator function is defined by default as a memberwise assignment of the class members. If assignment operator functions exist for base classes or class members, these operators are used when the compiler generates default copy assignment operators. See Copy by Assignment for more information. For more information on standard assignment operators, see Assignment Expression. ═══ 12.4.2. Overloaded Function Call ═══ The function call has syntax of the form: function-name ( [expression-list] ) and is considered a binary operator. The operands are function-name and an optional expression-list. The operator function operator() must be defined as a nonstatic member function. You cannot declare an overloaded function call operator that is a nonmember function. If you make the following call for the class object x: x (arg1, arg2, arg3) it is interpreted as x.operator( )(arg1, arg2, arg3) Unlike all other overloaded operators, you can provide default arguments and ellipses in the argument list for the function call operator. For example: class X { public: X& operator() (int = 5); }; For more information on the standard function call operator, see Function Call ( ). ═══ 12.4.3. Overloaded Subscripting ═══ An expression containing the subscripting operator has syntax of the form: identifier [ expression ] and is considered a binary operator. The operands are identifier and expression. The operator function operator[] must be defined as a nonstatic member function. You cannot declare an overloaded subscript operator that is a nonmember function. A subscripting expression for the class object x: x [y] is interpreted as x.operator[](y). It is not interpreted as operator[](x,y) because it is defined as a nonstatic member function. For more information on the standard subscripting operator, see Array Subscript [ ]. ═══ 12.4.4. Overloaded Class Member Access ═══ An expression containing the class member access -> (arrow) operator has syntax of the form: identifier -> name-expression and is considered a unary operator. The operator function operator->() must be defined as a nonstatic member function. The following restrictions apply to class member access operators: o You cannot declare an overloaded arrow operator that is a nonmember function. o You cannot overload the class member access . (dot) operator. Consider the following example of overloading the -> (arrow) operator: class Y { public: void f(); }; class X { public: Y* operator->(); }; X x; x->f(); Here x->f() is interpreted as: ( x.operator->() )-> f() . x.operator->() must return either a reference to a class object or a class object for which the overloaded operator-> function is defined or a pointer to any class. If the overloaded operator-> function returns a class type, the class type must not be the same as the class declaring the function, and the class type returned must contain its own definition of an overloaded -> operator function. For more information on the standard class member access arrow operator, see Arrow Operator. ═══ 12.4.5. Overloaded Increment and Decrement ═══ The prefix increment operator ++ can be overloaded for a class type by declaring a nonmember function operator with one argument of class type or a reference to class type, or by declaring a member function operator with no arguments. In the following example, the increment operator is overloaded in both ways: class X { int a; public: operator++(); // member prefix increment operator }; class Y { /* ... */ } operator++(Y& y); // nonmember prefix increment operator // Definitions of prefix increment operator functions // ... void main() { X x; Y y; ++x; // x.operator++ x.operator++(); // x.operator++ operator++(y); // nonmember operator++ ++y; // nonmember operator++ } The postfix increment operator ++ can be overloaded for a class type by declaring a nonmember function operator operator++() with two arguments, the first having class type and the second having type int. Alternatively, you can declare a member function operator operator++() with one argument having type int. The compiler uses the int argument to distinguish between the prefix and postfix increment operators. For implicit calls, the default value is zero. For example: class X { int a; public: operator++(int); // member postfix increment operator }; operator++(X x, int i); // nonmember postfix increment operator // Definitions of postfix increment operator functions // ... void main() { X x; x++; // x.operator++ // default zero is supplied by compiler x.operator++(0); // x.operator++ operator++(x,0); // nonmember operator++ } The prefix and postfix decrement operators follow the same rules as their increment counterparts. For more information on the standard postfix and prefix increment operators, see Increment ++. For more information on the standard postfix and prefix decrement operators, see Decrement - -. ═══ 12.4.6. Overloaded new and delete ═══ You can implement your own memory management scheme for a class by overloading the operators new and delete. The overloaded operator new must return a void*, and its first argument must have type size_t, which is defined in the standard header file . The overloaded operator delete must return a void type, and its first argument must be void*. The second argument for the overloaded delete operator is optional and, if present, it must have type size_t. You can only define one delete operator function for a class. The size argument is required because a class may inherit an overloaded new operator. The derived class can be a different size than the base class. The size argument ensures that the correct amount of storage space is allocated or deallocated for the object. When new and delete are overloaded within a class declaration, they are static member functions whether they are declared with the keyword static or not. Thus, they cannot be virtual functions. You can access the standard, nonoverloaded versions of new and delete within a class scope containing the overloading new and delete operators by using the :: (scope resolution) operator to provide global access. For more information on the class member operators new and delete, see Free Store. For more information on the standard new and delete operators, see new Operator and delete Operator. ═══ 13. Special Member Functions ═══ This chapter introduces the special member functions that are used to create, destroy, convert, initialize, and copy class objects. The following topics are discussed in this chapter: o Constructors o Destructors o Free Store o Temporary Objects o User-Defined Conversions o Initialization by Constructor o Copying Class Objects Related Information o C++ Classes o C++ Class Members and Friends o Functions ═══ 13.1. Constructors and Destructors Overview ═══ Because classes have complicated internal structures, including data and functions, object initialization and cleanup for classes is much more complicated than it is for simple data structures. Constructors and destructors are special member functions of classes that are used to construct and destroy class objects. Construction may involve memory allocation and initialization for objects. Destruction may involve cleanup and deallocation of memory for objects. Like other member functions, constructors and destructors are declared within a class declaration. They can be defined inline or external to the class declaration. Constructors can have default arguments. Unlike other member functions, constructors can have member initialization lists. The following restrictions apply to constructors and destructors: o Constructors and destructors do not have return types nor can they return values. o References and pointers cannot be used on constructors and destructors because their addresses cannot be taken. o Constructors cannot be declared with the keyword virtual. o Constructors and destructors cannot be declared static, const, or volatile. o Unions and aggregate classes cannot contain class objects that have constructors or destructors. Constructors and destructors obey the same access rules as member functions. For example, if a constructor is declared with the keyword protected, only derived classes and friends can use it to create class objects. Class member access is described in Member Access. The compiler automatically calls constructors when defining class objects and calls destructors when class objects go out of scope. A constructor does not allocate memory for the class object its this pointer refers to, but may allocate storage for more objects that its class object refers to. If memory allocation is required for objects, constructors can explicitly call the new operator. During cleanup, a destructor may release objects allocated by the corresponding constructor. To release objects, use the delete operator. Derived classes do not inherit constructors or destructors from their base classes, but they do call the constructor and destructor of base classes. Destructors can be declared with the keyword virtual. Constructors are also called when local or temporary class objects are created, and destructors are called when local or temporary objects go out of scope. You can call member functions from constructors or destructors. You can call a virtual function, either directly or indirectly, from a constructor or destructor. In this case, the function called is the one defined in the class or base class containing the constructor (or destructor), but not a function defined in any class derived from the class being constructed. This avoids the possibility of accessing an unconstructed object from a constructor or destructor. Related Information o Constructors o Destructors o Virtual Functions o Member Access o new Operator o delete Operator ═══ 13.1.1. Constructors ═══ A constructor is a member function with the same name as its class. For example: class X { public: X(); // constructor for class X }; Constructors are used to create, and can initialize, objects of their class type. Initialization of class objects using constructors is described in Initialization by Constructor. A default constructor is a constructor that either has no arguments, or, if it has arguments, all the arguments have default values. If no user-defined constructor exists for a class and one is needed, the compiler creates a default constructor, with public access, for that class. No default constructor is created for a class that has any constant or reference type members. Like all functions, a constructor can have default arguments. They are used to initialize member objects. If default values are supplied, the trailing arguments can be omitted in the expression list of the constructor. Note that if a constructor has any arguments that do not have default values, it is not a default constructor. A copy constructor is used to make a copy of one class object from another class object of the same class type. A copy constructor is called with a single argument that is a reference to its own class type. You cannot use a copy constructor with an argument of the same type as its class; you must use a reference. You can provide copy constructors with additional default arguments. If a user-defined copy constructor does not exist for a class and one is needed, the compiler creates a copy constructor, with public access, for that class. It is not created for a class if any of its members or base classes have an inaccessible copy constructor. If a class has a base class or members with constructors when it is constructed, the constructor for the base class is called, followed by any constructors for members. The constructor for the derived class is called last. Virtual base classes are constructed before nonvirtual base classes. When more than one base class exists, the base class constructors are called in the order that their classes appear in the base list. For more information, see Construction Order of Derived Class Objects. Examples of Constructors and Construction Order You cannot call constructors directly. You use a function style cast to explicitly construct an object of the specified type. Example of Explicitly Constructing an Object Related Information o Destructors o Constructors and Destructors Overview o Construction Order of Derived Class Objects o Default Arguments o References ═══ Example of Explicitly Constructing an Object ═══ /************************************************************************ * In the following example, a constructor is used as an initializer to create a named object. * ************************************************************************/ #include class X { public: X (int, int , int = 0); // constructor with default argument private: int a, b, c; int f(); }; X::X (int i, int j, int k) { a = i; b = j; c = k; } void main () { X xobject = X(1,2,3); // explicitly create and initialize // named object with constructor call } ═══ Examples of Constructors and Construction Order ═══ /************************************************************************ * The following code fragment shows two classes with constructors, default constructors, and copy constructors: class X { public: X(); // default constructor, no arguments X(int, int , int = 0); // constructor X(const X&); // copy constructor X(X); // error, incorrect argument type }; class Y { public: Y( int = 0); // default constructor with one // default argument Y(const Y&, int = 0); // copy constructor }; When more than one base class exists, the base class constructors are called in the order that their classes appear in the base list, as shown in the following example. Note that the construction of class D involves construction of the base classes B1, B2, and B3. The construction of base class B2 involves the construction of its class B1 member object. Thus, when class B2 is constructed, the constructor for class B1 is called in addition to B2's own constructor: * ************************************************************************/ class B1 { public: B1(); }; class B2 { public: B2(); B1 b1obj; }; class B3 { public: B3(); }; // ... class D : public B1, public B2, public B3 { public: D(); ~D(); }; void main () { D object; } /************************************************************************ * In the above example, the constructors for object are called in the following order: B1(); // first base constructor declared B1(); // member constructor for B2::b1obj B2(); // second base constructor declared B3(); // last base constructor declared D(); // derived constructor called last As explained above, the second call to the constructor of B1 followed by the call to the constructor of B2 is part of the construction of B2. * ************************************************************************/ ═══ 13.1.2. Destructors ═══ A destructor is a member function with the same name as its class prefixed by a ~ (tilde). For example: class X { public: X(); // constructor for class X ~X(); // destructor for class X }; A destructor takes no arguments and has no return type. Its address cannot be taken. Destructors cannot be declared const, volatile, or static. A destructor can be declared virtual or pure virtual. A union cannot have as a member an object of a class with a destructor. Destructors are usually used to deallocate memory and do other cleanup for a class object and its class members when the object is destroyed. A destructor is called for a class object when that object passes out of scope or is explicitly deleted. Class members that are class types can have their own destructors. Both base and derived classes can have destructors, although destructors are not inherited. If a base class or a member of a base class has a destructor and a class derived from that base class does not declare a destructor, a default destructor is generated. The default destructor calls the destructors of the base class and members of the derived class. Default destructors are generated with default public access. Destructors are called in the reverse order to constructors: 1. The destructor for a class object is called before destructors for members and bases are called. 2. Destructors for nonstatic members are called before destructors for base classes are called. 3. Destructors for nonvirtual base classes are called before destructors for virtual base classes are called. When an exception is thrown for a class object with a destructor, the destructor for the temporary object thrown is not called until control passes out of the catch block. For more information, see Constructors and Destructors in Exception Handling. Destructors are implicitly called when an automatic or temporary object passes out of scope. They are implicitly called at program termination for constructed external and static objects. Destructors are invoked when you use the delete operator for objects created with the new operator. Example of Destructors You can use a destructor explicitly to destroy objects, although this practice is not recommended. If an object has been placed at a specific address by the new operator, you can call the destructor of the object explicitly to destroy it. An explicitly called destructor cannot delete storage. Note: You can only call destructors for class types. You cannot call destructors for simple types. The call to the destructor in the following example causes the compiler to issue a warning: int * ptr; ptr -> int::~int(); // warning Related Information o Constructors and Destructors Overview o Constructors o Virtual Functions o Constructors and Destructors in Exception Handling o new Operator o delete Operator ═══ Example of Destructors ═══ /*********************************************************************** * The following example shows the use of destructors: * ************************************************************************/ #include class Y { private: char * string; int number; public: Y(const char* n,int a); // constructor ~Y() { delete[] string; } // destructor }; Y::Y(const char* n, int a) // define class Y constructor { string = strcpy(new char[strlen(n) + 1 ], n); number = a; } void main () { Y yobj = Y("somestring", 10); // create and initialize // object of class Y // ... // destructor ~Y is called before control returns from main() } ═══ 13.2. Free Store ═══ Free store is used for dynamic allocation of memory. The new and delete operators are used to allocate and deallocate free store, respectively. You can define your own versions of new and delete for a class by overloading them. You can supply the new and delete operators with additional arguments. You can also use the /Tm option to enable the debug versions of these operators. See Debug Versions of new and delete for more information on these versions. When new and delete operate on class objects, the class member operator functions new and delete are called, if they have been declared. If you create a class object with the new operator, the operator function operator new() (if it has been declared) is called to create the object. An operator new() for a class is always a static class member, even if it is not declared with the keyword static. It has a return type void* and its first argument must be the size of the object type and have type size_t. It cannot be virtual. Type size_t is an implementation dependent unsigned integral type defined in . For more information about size_t, see the IBM C/C++ Tools: Programming Guide. When you overload the new operator, you must declare it as a class member, returning type void*, with first argument size_t, as described above. You supply additional arguments in the declaration of operator new(). Use the placement syntax. to specify values for these arguments in an allocation expression The delete operator destroys an object created by the new operator. The operand of delete must be a pointer returned by new. If delete is called for an object with a destructor, the destructor is invoked before the object is deallocated. If you destroy a class object with the delete operator, the operator function operator delete() (if it has been declared) is called to destroy the object. An operator delete() for a class is always a static member, even if it is not declared with the keyword static. Its first argument must have type void*. Because operator delete() has a return type void, it cannot return a value. It cannot be virtual. When you overload the delete operator, you must declare it as class member, returning type void, with first argument having type void*, as described above. You can add a second argument of type size_t to the declaration. You can only have one operator delete() for a single class. Examples of operator new() and operator delete() The result of trying to access a deleted object is undefined because the value of the object can change after deletion. If new and delete are called for a class object that does not declare the operator functions new and delete, or they are called for a nonclass object, the global operators new and delete are used. The global operators new and delete are provided in the C++ library. Related Information o new Operator o delete Operator o Overloaded new and delete o Debug Versions of new and delete ═══ Examples of operators new() and delete() ═══ /************************************************************************ * The following example shows two overloaded new operator functions. * ************************************************************************/ #include class X { public: void* operator new(size_t); void* operator new(size_t, int); }; void main () { X* ptr1 = new X; // calls X::operator new(sizeof(X)) X* ptr2 = new(10) X; // calls X::operator // new(sizeof(X),10) } /************************************************************************ * The following example shows the declaration and use of the operator functions operator new() and operator delete(): * ************************************************************************/ #include class X { public: void* operator new(size_t); void operator delete(void*); // single argument }; class Y { public: void operator delete(void*, size_t); // two arguments }; void main () { X* ptr = new X; delete ptr; // call X::operator delete(void*) Y* yptr; // ... delete yptr; // call Y::operator delete(void*, size_t) // with size of Y as second argument } ═══ 13.2.1. Debug Versions of new and delete ═══ C/C++ Tools provides special versions of new and delete to assist you in debugging memory management problems. These versions can help you find where memory is being incorrectly allocated, written to, or freed. To enable the debug memory management functions, use the /Tm option, which also defines the macro __DEBUG_ALLOC__. The debug versions of new and delete, as well as of the C library functions (malloc and so on), are automatically called in place of the regular functions in your code. Do not parenthesize any calls to these functions, because parentheses disable the definition of the function name to the debug function name. To each call to new, the compiler adds 2 parameters equivalent to the current __FILE__ and __LINE__ macros. They are inserted as the first two parameters in the placement syntax. As a result, the global and class-specific versions of operator new change from: operator new(size_t); operator new(size_t , additional_parameters ); to: operator new(size_t, const char *, size_t); operator new(size_t, const char *, size_t , additional_parameters ); The compiler adds the same parameters to each delete call, changing all global and class-specific versions of delete from: operator delete(void *); operator delete(void * , size_t ); to: operator delete(void *, const char *, size_t); operator delete(void *, const char *, size_t , size_t ); The debug versions also automatically call the C library function _heap_check. This function checks all memory blocks allocated or freed by debug memory management functions to make sure that no overwriting has occurred outside the bounds of allocated blocks or in a free memory block. You can also call _heap_check explicitly. You can also call the C library function _dump_allocated to print out information about each memory block currently allocated by the debug memory management functions. Both _heap_check and _dump_allocated are only available when the __DEBUG_ALLOC__ macro is defined, and are described in the IBM C/C++ Tools C Library Reference. All output from these functions is sent to the OS/2 file handle 2, which is usually associated with stderr. Note: The information provided by these functions is Diagnosis, Modification, and Tuning information only. It is not intended to be used as a programming interface. You may need to include the header file to include the prototypes of the debug malloc and free code that the debug versions of new and delete use. Important The changes described above take place for all occurrences of new and delete whether global or specific to a class. If you have provided member new or delete functions, you must make code changes before compiling with /Tm. You can use the __DEBUG_ALLOC__ macro for conditional compilation. For more information on debug memory management functions in the C library, see the IBM C/C++ Tools C Library Reference. ═══ 13.3. Temporary Objects ═══ It is sometimes necessary for the compiler to create temporary objects. They are used during reference initialization and during evaluation of expressions including standard type conversions, argument passing, function returns, and evaluation of the throw expression. When a temporary object is created to initialize a reference variable, the name of the temporary object has the same scope as that of the reference variable. When a temporary object is created during the evaluation of an expression, it exists until there is a break in the flow of control of the program. If a temporary object is created for a class with constructors, the compiler calls the appropriate (matching) constructor to create the temporary object. When a temporary object is destroyed and a destructor exists, the compiler calls the destructor to destroy the temporary object. When you exit from the scope in which the temporary object was created, it is destroyed. If a reference is bound to a temporary object, the temporary object is destroyed when the reference passes out of scope unless it is destroyed earlier by a break in the flow of control. For example, a temporary object created by a constructor initializer for a reference member is destroyed on leaving the contructor. Examples of Temporary Objects Use the /Wgnr option to flag the points where temporary objects are generated. Related Information o Constructors o Destructors o References o Initializing References o Expressions and Operators o Functions o Using Exception Handling ═══ Examples of Temporary Objects ═══ /************************************************************************ * The following example shows two expressions in which temporary objects are constructed: * ************************************************************************/ class Y { public: Y(int); Y(Y&); ~Y(); }; Y add(Y y) { /* ... */ } void main () { Y obj1(10); Y obj2 = add(Y(5)); // one temporary created obj1 = add(obj1); // two temporaries created } /************************************************************************ * In the above example, a temporary object of class type Y is created to construct Y(5) before it is passed to the function add(). Because obj2 is being constructed, the function add() can construct its return value directly into obj2, so another temporary object is not created. A temporary object of class type Y is created when obj1 is passed to the function add(). Because obj1 has already been constructed, the function add() constructs its return value into a temporary object. This second temporary object is then assigned to obj1 using an assignment operator. * ************************************************************************/ ═══ 13.4. User-Defined Conversions ═══ User-defined conversions allow you to specify object conversions with constructors or with conversion functions. User-defined conversions are implicitly used in addition to standard conversions for conversion of initializers, functions arguments, function return values, expression operands, expressions controlling iteration, selection statements, and explicit type conversions. There are two types of user-defined conversions: o Conversion by Constructor o Conversion Functions Related Information o Type Conversions o Constructors and Destructors Overview o Constructors o C++ Classes o Functions ═══ 13.4.1. Conversion by Constructor ═══ You can call a class constructor with a single argument to convert from the argument type to the type of the class. At most one user-defined conversion, either a constructor or conversion function, is implicitly applied to a class object. When you call a constructor with an argument and you have not defined a constructor accepting that argument type, only standard conversions are used to convert the argument to another argument type acceptable to a constructor for that class. Other constructors or conversions functions are not called to convert the argument to a type acceptable to a constructor defined for that class. Example of Conversion by Constructor Related Information o Conversion Functions o Constructors and Destructors Overview o Constructors o User-Defined Conversions o Type Conversions ═══ Example of Conversion by Constructor ═══ /************************************************************************ * The following example shows conversion by constructor: * ************************************************************************/ class Y { int a,b; char* name; public: Y(int i); Y(const char* n, int j = 0); }; void add(Y); // ... void main () { // code equivalent code Y obj1 = 2; // obj1 = Y(2) Y obj2 = "somestring"; // obj2 = Y("somestring",0) obj1 = 10; // obj1 = Y(10) add(5); // add(Y(5)) } ═══ 13.4.2. Conversion Functions ═══ You can define a member function of a class, called a conversion function, that converts from the type of its class to another specified type. Syntax of a Conversion Function The conversion function specifies a conversion from the class type the conversion function is a member of, to the type specified by the name of the conversion function. Classes, enumerations, and typedef names cannot be declared or defined as part of the function name. Conversion functions have no arguments, and the return type is implicitly the conversion type. Conversion functions can be inherited. You can have virtual conversion functions but not static ones. Only one user-defined conversion is implicitly applied to a single value. User-defined conversions must be unambiguous, or they are not called. If a conversion function is declared with the keyword const, the keyword has no affect on the function except for acting as a tie-breaker when there is more than one conversion function that could be applied. Specifically, if more than one conversion function could be applied, all of these functions are compared. If any of these functions is declared with the keyword const, const is ignored for the purposes of this comparison. If one of these functions is a best match, this function is applied. If there is no best match, the functions are compared again, but this time const is not ignored. Example of a Conversion Function Related Information o Conversion by Constructor o Functions o Type Conversions o volatile and const Qualifiers o Virtual Functions ═══ Syntax of a Conversion Function ═══ A conversion function has the following syntax: >>──┬─────────┬──operator──┬──────────┬──conversion_type──┬───┬──(──)──> └─class::─┘ ├─const────┤ ├─*─┤ └─volatile─┘ └─&─┘ >──┬─────────────────────┬──>< └─{──function_body──}─┘ ═══ Example of a Conversion Function ═══ /************************************************************************ * The following code fragment shows a conversion function called operator int(): * ************************************************************************/ class Y { int b; public: operator int(); }; Y::operator int() {return b;} void f(Y obj ) { // each value assigned is converted by Y::operator int() int i = int(obj); int j = (int)obj; int k = i + obj; } ═══ 13.5. Initialization by Constructor ═══ A class object with a constructor must be explicitly initialized or have a default constructor. Explicit initialization using a constructor is the only way, except for aggregate initialization, to initialize nonstatic constant and reference class members. A class object that has no constructors, no virtual functions, no private or protected members, and no base classes is called an aggregate. Aggregates are described in Structures and Unions. Class objects with constructors can be initialized with a parenthesized expression list. This list is used as an argument list for the call of a constructor that is used to initialize the class. You can also call a constructor with a single initialization value using the = operator. Because this type of expression is an initialization, not an assignment, the assignment operator function, if one exists, is not called. This value is used as a single argument for the call of a constructor. The type of the single argument must match the type of the first argument to the constructor. If the constructor has remaining arguments, these arguments must have default values. Syntax of an Explicit Initializer by Constructor Constructors can initialize their members in two different ways. A constructor can use the arguments passed to it to initialize member variables in the constructor definition: complx( double r, double i = 0.0) {re = r; im = i;} Or a constructor can have an initializer list within the definition but prior to the function body: complx ( double r, double i = 0) : re(r), im(i) { /* ... */ } Both methods assign the argument values to the appropriate data members of the class. The second method must be used to initialize base classes from within a derived class to initialize constant and reference members and members with constructors. Example of Explicit Initialization by Constructor Related Information o Initializing Base Classes and Members o Construction Order of Derived Class Objects o Constructors and Destructors Overview o Constructors o C++ Classes ═══ Syntax of an Explicit Initializer by Constructor ═══ The syntax for an initializer that explicitly initializes a class object with a constructor is: >>──┬─(──expression──)───────────────────┬──>< └─=──┬─expression──────────────────┬─┘ │ ┌─,──────────┐ │ │  │ │ └─{────expression─┴──┬───┬──}─┘ └─,─┘ ═══ Example of Explicit Initialization by Constructor ═══ /************************************************************************ * The following example shows the declaration and use of several constructors that explicitly initialize class objects: * ************************************************************************/ #include class complx { double re, im ; public: complx(); // default constructor complx(const complx& c) {re = c.re; im = c.im;} // copy constructor complx( double r, double i = 0.0) {re = r; im = i;} // constructor with default trailing argument void display() { cout << "re = "<< re << " im = " << im << endl; } }; void main () { complx one(1); // initialize with complx(double, double) complx two = one; // initialize with a copy of one // using complx::complx(const complx&) complx three = complx(3,4); // construct complx(3,4) // directly into three complx four; // initialize with default constructor complx five = 5; // complx(double, double) & construct // directly into five one.display(); two.display(); three.display(); four.display(); five.display(); } /************************************************************************ * The above example produces the following output: re = 1 im = 0 re = 1 im = 0 re = 3 im = 4 re = 0 im = 0 re = 5 im = 0 * ************************************************************************/ ═══ 13.5.1. Initializing Base Classes and Members ═══ You can initialize immediate base classes and derived class members that are not inherited from base classes by specifying initializers in the constructor definition prior to the function body. Syntax of a Constructor Initializer In a constructor that is not inline, include the initialization list as part of the function definition, not as part of the class declaration. For example: class B1 { int b; public: B1(); B1(int i) : b(i) { /* ... */ } // inline constructor }; class B2 { int b; protected: B2(); B2(int i); // noninline constructor }; // B2 constructor definition including initialization list B2::B2(int i) : b(i) { /* ...*/ } // ... class D : public B1, public B2 { int d1, d2; public: D(int i, int j) : B1(i+1), B2(), d1(i) {d2 = j;} }; If you do not explicitly initialize a base class or member that has constructors by calling a constructor, the compiler automatically initializes the base class or member with a default constructor. In the above example, if you leave out the call B2() in the constructor of class D (as shown below), a constructor initializer with an empty expression list is automatically created to initialize B2. Thus, the constructors for class D, shown above and below, result in the same construction of an object of class D. class D : public B1, public B2 { int d1, d2; public: // call B2() generated by compiler D(int i, int j) : B1(i+1), d1(i) {d2 = j;} }; Note: You must declare base constructors with the access specifiers public or protected to enable a derived class to call them. Example of Base Constructors and Derivation Related Information o Construction Order of Derived Class Objects o Initialization by Constructor o Constructors and Destructors Overview o Constructors o Member Access ═══ Syntax of a Constructor Initializer ═══ The syntax for a constructor initializer is: ┌─,─────────────────────────────────────────────────┐ │ ┌─────────────────────────┐ │   │ │ >>──:────┬─identifier─┬──(───┬───────────────────────┬┴──)─┴──>< └─class_name─┘ └─assignment_expression─┘ ═══ Example of Base Constructors and Derivation ═══ /************************************************************************ * The following example shows how to call base constructors from derived classes: * ************************************************************************/ class B1 { int b; public: B1(); B1(int i) : b(i) { /* ... */ } }; class B2 { int b; protected: B2(); B2(int i); }; B2::B2(int i) : b(i) { /* ... */ } class B4 { public: B4(); // public constructor for B4 int b; private: B4(int); // private constructor for B4 }; // . // . // . class D : public B1, public B2, public B4 { int d1, d2; public: D(int i, int j) : B1(i+1), B2(i+2) , B4(i) {d1 = i; d2 = j; } // error, attempt to access private constructor B4() D(int i, int j) : B1(i+1), B2(i+2) {d1 = i; d2 = j;} // valid, calls public constructor for B4 }; ═══ 13.5.2. Construction Order of Derived Class Objects ═══ When a derived class object is created using constructors, it is created in the following order: 1. Virtual base classes are initialized, in the order they appear in the base list. 2. Nonvirtual base classes are initialized, in declaration order. 3. Class members are initialized in declaration order (regardless of their order in the initialization list). 4. The body of the constructor is executed. In the following code fragment, the constructor for class B1 is called before the member d1 is initialized. Thus, the value passed to the constructor for class B1 is undefined. class B1 { int b; public: B1(); B1(int i) {b = i;} }; class D : public B1 { int d1, d2; public: D(int i, int j) : d1(i), B1(d1) {d2 = j;} // d1 is not initialized in call B1::B1(d1) }; Related Information o Initializing Base Classes and Members o Initialization by Constructor o Constructors and Destructors Overview o Constructors o Derivation ═══ 13.6. Copying Class Objects ═══ You can copy one class object to another object of the same type by either assignment or initialization. Copy by assignment is implemented with an assignment operator function. If you do not define the assignment operator, it is defined as memberwise assignment. Copy by initialization is implemented with a copy constructor. If you do not define a copy constructor, it is defined as memberwise initialization of members of its class. Memberwise assignment and memberwise initialization mean that, if a class has a member that is a class object, the assignment operator and copy constructor of that class object are used to implement assignment and initialization of the member. Restrictions: A default assignment operator cannot be generated for a class that has: o A nonstatic constant or reference data member o A nonstatic data member or base class whose assignment operator is not accessible o A nonstatic data member or base class with no assignment operator and for which a default assignment operator cannot be generated A default copy constructor cannot be generated for a class that has: o A nonstatic data member or base class whose copy constructor is not accessible o A nonstatic data member or base class with no copy constructor and for which a default copy constructor cannot be generated Related Information o Copy by Assignment o Copy by Initialization o Constructors and Destructors Overview o Constructors o Overloaded Assignment ═══ 13.6.1. Copy by Assignment ═══ If you do not define an assignment operator and one is required, a default assignment operator is defined. If you do not define an assignment operator and one is not required, a default assignment operator is declared but not defined. If an assignment operator that takes a single argument of a class type exists for a class, a default assignment operator is not generated. Copy by assignment is used only in assignment. You can define an assignment operator for a class with a single argument that is a constant reference to that class type, only if all its base classes and members have assignment operators that accept constant arguments. For example: class B1 { public: B1& operator=(const B1&); }; class D: public B1 { public: D& operator=(const D&); }; D& D::operator=(const D& dobj) {D dobj2 = dobj; return dobj2;} Otherwise, you can define an assignment operator for a class with a single argument that is a reference to that class type. For example: class Z { public: Z& operator=( Z&); }; Z& Z::operator=(Z& zobj) {Z zobj2 = zobj; return zobj2;} The default assignment operator for a class is a public class member. The return type is a reference to the class type it is a member of. Related Information o Assignment Expression o Overloaded Assignment o Copy by Initialization o C++ Classes ═══ 13.6.2. Copy by Initialization ═══ You can define a copy constructor for a class. If you do not define a copy constructor and one is required, a default copy constructor is defined. If you do not define a copy constructor, and one is not required, a default copy constructor is declared but not defined. If a class has a copy constructor defined, a default copy constructor is not generated. Copy by initialization is used only in initialization. You can define a copy constructor for a class with a single argument that is a constant reference to a class type only if all its base classes and members have copy constructors that accept constant arguments. For example: class B1 { public: B1(const B1&) { /* ... */ } }; class D: public B1 { public: D(const D&); }; D::D(const D& dobj):B1(dobj) { /* ... */ } Otherwise, you can define a copy constructor with a single reference to a class type argument. For example: class Z { public: Z(Z&); }; Z::Z(Z&) { /* ...*/ } The default copy constructor for a class is a public class member. Related Information o Initialization by Constructor o Constructors o Copy by Assignment o C++ Classes ═══ 14. Inheritance ═══ In C++, you can create classes from existing classes using the object-oriented programming technique called inheritance. Inheritance allows you to define an is a relationship between classes. When members are inherited, they can be used as if they are members of the class that inherits them. This chapter introduces inheritance and describes: o Inheritance Overview o Derivation o Inherited Member Access o Multiple Inheritance o Virtual Functions o Abstract Classes Related Information o C++ Classes o C++ Class Members and Friends ═══ 14.1. Inheritance Overview ═══ C++ implements inheritance through the mechanism of derivation. Derivation allows you to reuse code by creating new classes, called derived classes, that inherit properties from one or more existing classes, called base classes. A derived class inherits the properties, including data and function members, of its base class. You can also add new data members and member functions to the derived class. You can modify the implementation of existing member functions or data by overriding base class member functions or data in the newly derived class. Multiple inheritance allows you to create a derived class that inherits properties from more than one base class. Because a derived class inherits members from all its base classes, ambiguities can result. For example, if two base classes have a member with the same name, the derived class cannot implicitly differentiate between the two members. Note that, when you are using multiple inheritance, the access to names of base classes may be ambiguous. Examples of Single and Multiple Inheritance Multiple inheritance allows you to have more than one base class for a single derived class. You can create an interconnected inheritance graph of inherited classes by using derived classes as base classes for other derived classes. You can build an inheritance graph through the process of specialization, in which derived classes are more specialized than their base classes. You can also work in the reverse direction and build an inheritance graph through generalization. If you have a number of related classes that share a group of properties, you can generalize and build a base class to embody them. The group of related classes becomes the derived classes of the new base class. A direct base class is a base class that appears directly as a base specifier in the declaration of its derived class. A direct base class is analogous to a parent in a hierarchical graph. An indirect base class is a base class that does not appear directly in the declaration of the derived class but is available to the derived class through one of its base classes. An indirect base class is analogous to a grandparent or great grandparent or great-great grandparent in a hierarchical graph. For a given class, all base classes that are not direct base classes are indirect base classes. Polymorphic functions are functions that can be applied to objects of more than one type. In C++, polymorphic functions are implemented in two ways: o Overloaded functions are statically bound at compile time, as discussed in Overloading Functions. o C++ provides virtual functions. A virtual function is a function that can be called for a number of different user-defined types that are related through derivation. Virtual functions are bound dynamically at run time. Typically, a base class has several derived classes, each requiring its own customized version of a particular operation. It is difficult for a base class to implement member functions that are useful for all of its derived classes. A base class would have to determine which derived class an object belonged to before it could execute the applicable code for that object. When a virtual function is called, the compiler executes the function implementation associated with the object that the function is called for. The implementation of the base class is only a default that is used when the derived class does not contain its own implementation. Related Information o Derivation o Multiple Inheritance o Virtual Functions o C++ Classes o C++ Class Members and Friends ═══ 14.1.1. Examples of Single and Multiple Inheritance ═══ Suppose you have defined a shape class to describe and operate on geometric shapes. Now suppose you want to define a circle class. Because you have existing code that operates on the shape class, you can use inheritance to create the circle class. You can redefine operations in the derived circle class that were originally defined in the shape base class. When you manipulate an object of the circle class, these redefined function implementations are used. For example: class shape { char* name; int xpoint, ypoint; public: virtual void rotate(int); virtual void draw(); void display() const; }; class circle: public shape // derive class circle from class shape { int xorigin, yorigin; int radius; public: void rotate(int); void draw(); void display() const; }; In the above example, class circle inherits the data members name, xpoint and ypoint, as well as the member functions display(), rotate(), and draw() from class shape. Because the member functions rotate() and draw() are declared in class shape with the keyword virtual, you can provide an alternative implementation for them in class circle. You can also provide an alternative implementation for the nonvirtual member function display() in class circle. When you manipulate an argument of type circle using a pointer to shape, and call a virtual member function, the member function defined in the derived class overrides the base-class member function. A similar call to a nonvirtual member function will call the member function defined in the base class. In addition to inheriting the members of class shape, class circle has declared its own data members, xorigin, yorigin, and radius. The key difference between virtual and nonvirtual member functions is that, when you treat the circle class as if it were a shape, the implementations of the virtual functions rotate() and draw() defined in class circle are used, rather than those originally defined in class shape. Because display() is a nonvirtual member function, the original implementation of display() defined in class shape is used. Multiple inheritance allows you to create a derived class that inherits properties from more than one base class. For example, in addition to the shape class, described above, you could also have a symbol class. Because a circle is both a shape and a symbol, you can use multiple inheritance to reflect this relationship. If the circle class is derived from both the shape and symbol classes, the circle class inherits properties from both classes. class symbol { char* language; char letter; int number; public: virtual void write(); virtual void meaning(); }; class shape { char* name; int xpoint, ypoint; public: virtual void rotate(int); virtual void draw(); void display() const; }; class circle: public symbol, public shape { int xorigin, yorigin; int radius; public: void rotate(int); void draw (); void write(); void meaning(); void display() const; }; In the above example, class circle inherits the members name, xpoint, ypoint, display(), rotate(), and draw() from class shape and also inherits the members language, letter, number, write(), and meaning() from class symbol. ═══ 14.2. Derivation ═══ Inheritance is implemented in C++ through the mechanism of derivation. Derivation allows you to derive a class, called a derived class, from another class, called a base class. In the declaration of a derived class, you list the base classes of the derived class. The derived class inherits its members from these base classes. All classes that appear in the list of base classes must be previously defined classes. Syntax of a Derived Class Incompletely declared classes are not allowed in base lists. For example: class X; // incomplete declaration of class X class Y: public X // error { }; When you derive a class, the derived class inherits class members of the base class. You can refer to inherited members (base class members) as if they were members of the derived class. If you redefine base class members in the derived class, you can still refer to the base class members by using the :: (scope resolution) operator. You can manipulate a derived class object as if it were a base class object. You can use a pointer or a reference to a derived class object in place of a pointer or reference to its base class. For example, you can pass a pointer or reference to a derived class object D to a function expecting a pointer or reference to the base class of D. You do not need to use an explicit cast to achieve this; a standard conversion is performed. You can implicitly convert a pointer to a derived class to point to a base class. You can also implicitly convert a reference to a derived class to a reference to a base class. The reverse case is not allowed. You cannot implicitly convert a pointer or a reference to a base class object to a pointer or reference to a derived class. Examples of Derived Classes If a member of a derived class and a member of a base class have the same name, the base class member is hidden in the derived class. If a member of a derived class has the same name as a base class, the base class name is hidden in the derived class. In both cases, the name of the derived class member is called the dominant name. Related Information o Inheritance Overview o C++ Classes o Scope Resolution Operator o Multiple Inheritance ═══ Examples of Derived Classes ═══ /************************************************************************ * You can refer to inherited members (base class members) as if they were members of the derived class: * ************************************************************************/ class base { public: int a,b; }; class derived : public base { public: int c; }; void main() { derived d; d.a = 1; // base::a d.b = 2; // base::b d.c = 3; // derived::c } /************************************************************************ * The derived class can also add new class members and redefine existing base class members. In the above example, the two inherited members, a and b, of the derived class d, in addition to the derived class member c, are assigned values. For example: * ************************************************************************/ #include class base { public: char* name; void display(char* i) {cout << i << endl;} }; class derived : public base { public: char* name; void display(char* i){cout << i << endl;} }; void main() { derived d; // create derived class object d.name = "Derived Class"; // assignment to derived::name d.base::name = "Base Class"; // assignment to base::name // call derived::display(derived::name) d.display(d.name); // call base::display(base::name) d.base::display(d.base::name); } /************************************************************************ * In the following example, d, a pointer to a derived class object is assigned to bptr, a pointer to a base class object. A call is made to display() using bptr. Even though bptr has a type of pointer to base, in the body of display() the name member of derived is manipulated: * ************************************************************************/ #include class base { public: char* name; void display(char* i) {cout << i << endl;} }; class derived : public base { public: char* name; void display(char* i){cout << i << endl;} }; void main() { derived d; // standard conversion from derived* to base* base* bptr = ─"─; // call base::display(base::name) bptr->display(bptr->name); } ═══ Syntax of a Derived Class Declaration ═══ The syntax for the list of base classes is: >>──derived-class──:──> ┌─,───────────────────────────────────────────────────┐  │ >────┬────────────────────────────┬──complete-class-name─┴──>< ├─virtual──┬───────────┬─────┤ │ ├─public────┤ │ │ ├─private───┤ │ │ └─protected─┘ │ └─┬─public────┬──┬─────────┬─┘ ├─private───┤ └─virtual─┘ └─protected─┘ The qualified-class-specifier must be a class that has been previously declared in a class declaration as described in Declaring Class Objects. Access specifiers are described in Member Access. The virtual keyword can be used to declare virtual base classes. The following example shows the declaration of the derived class D and the base classes V, B1, and B2. The class B1 is both a base class and a derived class because it is derived from class V and is a base class for D. class V { /* ... */ }; class B1 : virtual public V { /* ... */ }; class B2 { /* ... */ }; class D : public B1, private B2 { /* ... */ }; ═══ 14.3. Inherited Member Access ═══ Access specifiers, as described in Member Access, control the level of access to noninherited class members. The access for an inherited member is controlled in three ways: o When you declare a member in a base class, you can specify a level of access using the keywords public, private, and protected. o When you derive a class, you can specify the access level for the base class in the base list. o You can also restore the access level of inherited members. See Derivation Access of Base Classes for an example. Resolution of member names does not depend on the level of access associated with each class member. Consider the following example: class A { private: int a; }; class B { public: int a; }; class C : public A, public B { void f() { a = 0; } // ambiguous - is it A::a or B::a? }; In this example, class A has a private member a, and class B has a public member a. Class C is derived from both A and B. C does not have access to A::a, but a in the body of f() can still resolve to either A::a or B::a. Thus, a is ambiguous in the body of f(). If a class is derived publicly from a base class, a protected static base class member can be accessed by members and friends of any classes derived from that base class. A protected nonstatic base class member can be accessed by members and friends of any classes derived from that base class by using one of the following: o A pointer to a directly or indirectly derived class o A reference to a directly or indirectly derived class o An object of a directly or indirectly derived class If a class is derived privately from a base class, all protected base class members become private members of the derived class. Examples of Inherited Member Access Rules Related Information o Derivation Access of Base Classes o Access Declarations o Access Resolution o Member Access o Derivation o C++ Classes ═══ 14.3.1. Derivation Access of Base Classes ═══ When you declare a derived class, an access specifier can precede each base class in the base list of the derived class. This does not alter the access attributes of the individual members of a base class as seen by the base class, but allows the derived class to restore the access attributes of the members of a base class. You can derive classes using any of the three access specifiers: o In a public base class, public and protected members of the base class remain public and protected members of the derived class. o In a private base class, public and protected members of the base class become private members of the derived class. o In a protected base class, public and protected members of the base class are protected members of the derived class. In all cases, private members of the base class remain private. Private members of the base class cannot be used by the derived class unless friend declarations within the base class explicitly grant access to them. You can use both a structure and a class as base classes in the base list of a derived class declaration. If the base class is declared with the keyword class, its default access specifier in the base list of a derived class is private. If the base class is declared with the keyword struct, its default access specifier in the base list of a derived class is public. Examples of Public and Private Derivation Members and friends of a class can implicitly convert a pointer to an object of that class to a pointer to either: o A direct private base class o A protected base class (either direct or indirect) Related Information o Access Declarations o Access Resolution o Member Access o Derivation o C++ Classes ═══ Examples of Public and Private Derivation ═══ In the following example, class d is derived publicly from class b. Class b is declared a public base class by this declaration. class b { // ... }; class d : public b // public derivation { // ... }; In the following example, private derivation is used by default because no access specifier is used in the base list: struct bb { // ... }; class dd : bb // private derivation { // ... }; ═══ 14.3.2. Access Declarations ═══ You can restore access to members of a base class using an access declaration. It allows you to change the access of a public member of a private or protected base class back to public. You can also change the access of a protected member of a private base class back to protected. Access is adjusted by using the base class member qualified name in the public or protected declarations of the derived class. You only use access declarations to restore base class access. You cannot change the access to a member to give it more access than it was originally declared with. You cannot change the access of a private member to public or to protected. You cannot change the access of a protected member to public. An access declaration cannot be used to restrict access to a member that is accessible in a base class. It is redundant to use an access declaration to change the access to a public member of a public base class to public, or to change the access to a protected member of a protected base class to protected. Examples of Access Declarations Access declarations can only be used to adjust the access of a member of a base class. The base class that an access declaration appears in can be directly or indirectly inherited by the derived class. You cannot adjust the access to a base class member if a member with the same name exists in a class derived from that base class. If you use an access declaration to adjust the access to an overloaded function, the access is adjusted for all functions with that name in the base class. Related Information o Derivation Access of Base Classes o Access Resolution o Member Access o Derivation o Overloading Functions o C++ Classes ═══ Examples of Access Declarations ═══ /************************************************************************ * In the following example, the member b of the base class base is declared public in its base class declaration. Class derived is derived privately from class base. The access declaration in the public section of class derived restores the access level of the member b back to public. * ************************************************************************/ #include class base { char a; public: char c, b; void bprint(); }; class derived: private base { char d; public: char e; base::b; // restore access to b in derived void dprint(); derived(char ch) { base::b = ch; } }; void print(derived& d) { cout << " Here is d " << d.b << endl; } void main() { derived obj('c'); print(obj); } /************************************************************************ * The external function print(derived&) can use the member b of base because the access of b has been restored to public. The external function print(derived&) can also use the members e and dprint() because they are declared with the keyword public in the derived class. The derived class member dprint() can use the members of its own class, d and e, in addition to the inherited members, b, c, and bprint(), that are declared with the keyword public in the base class. The base class member bprint() can use all the members of its own class, a, b, and c. You can also use an access declaration in a nested class. For example: class B { public: class N // nested class { public: int i; // public member }; }; class D: private B::N // derive privately { public: B::N::i; // restores access to public }; You cannot convert a pointer to a derived class object to a pointer to a base class object if the base class is private or protected. For example: class B { /* ... */ }; class D : private B { /* ... */ }; // private base class void main () { D d; B* ptr; ptr = ─"─; // error } * ************************************************************************/ ═══ 14.3.3. Access Resolution ═══ Access resolution is the process by which the accessibility of a particular class member is determined. Accessibility is dependent on the context. For example, a class member can be accessible in a member function but inaccessible at file scope. The following describes the access resolution procedure used by the compiler. In general, two scopes must be established before access resolution is applied. These scopes reduce an expression or declaration into a simplified construct to which the access rules are applied. Access rules are described in Member Access. These scopes are: Call scope The scope that encloses the expression or declaration that uses the class member. Reference scope The scope that identifies the class. For example, in the following code: class B { int member; }; // declaration class A : B {} // declaration void main() { A aobject; // declaration aobject.member = 10; // expression } the reference scope for member is the type of aobject, that is class type A. Reference scope is chosen by simplifying the expression (or declaration) containing the member. An expression can be thought of as being reduced to a simple expression of the form obj.member where obj is the reference scope. Reference scope is selected as follows: o If the member is qualified with . or ->, the reference scope is the type of the object that is immediately to the left of the . or -> operator closest to the member. Unqualified members are treated as if they are qualified with From heading: "This this Pointer" this->. o If the member is a type member or a static member and is qualified with :: (the scope resolution operator), the reference scope is the type immediately to the left of the :: operator closest to the member. o Otherwise, the reference scope is the call scope. The call scope and the reference scope determine the accessibility of a class member. Once these scopes are resolved, the effective access of the member is determined. Effective access is the access of the member as it is seen from the reference scope. It is determined by taking the original access of the member in its scope as the effective access and changing it as the class hierarchy is traversed from the member's class to the reference scope. Effective access is altered as the class hierarchy is traversed for each derivation by the following: o The derivation access of a base class (see Derivation Access of Base Classes) o Access declarations that are applied to the members (see Access Declarations) o Friendships that are granted to the call scope (see Member Access) After effective access is determined for a member, the access rules are applied as if the effective access were the original access of the member. A member is only accessible if the access rules say that it is. Example of Access Resolution Related Information o Derivation Access of Base Classes o Access Declarations o Member Access o Derivation o Overloading Functions o Scope Resolution Operator o C++ Classes ═══ Example of Access Resolution ═══ The following example demonstrates the access resolution procedure. class A { public: int a; }; class B : private A { friend void f (B*); }; void f(B* b) { b->a = 10; // is 'a' accessible to f(B*) ? } The following steps occur to determine the accessibility of A::a in f(B*): 1. The call scope and reference scope of the expression b->a are determined: a. The call scope is the function f(B*). b. The reference scope is class B. 2. The effective access of member a is determined: a. Because the original access of the member a is public in class A, the initial effective access of a is public. b. Because B inherits from A privately, the effective access of a inside class B is private. c. Because class B is the reference scope, the effective access procedure stops here. The effective access of a is private. 3. The access rules are applied. The rules state that a private member can be accessed by a friend or a member of the member's class. Because f(B*) is a friend of class B, f(B*) can access the private member a. ═══ Examples of Inherited Member Access Rules ═══ /************************************************************************ * The following example demonstrates inherited member access rules. * ************************************************************************/ class B { int a; public: int b,c; void f(int) {} protected: int d; void g(int) {} }; class D1 : public B { int a; public: int b; void h(int i ) { g(i); // valid, protected B::g(int) B::b = 10; // valid, B::b (not local b) d = 5 ; // valid, protected B::d } }; class D2 : private B { int e; public: B::c; // modify access to B::c void h(int i) { d = 5; } // valid,protected B::d }; void main( ) { int i= 1; // declare and initialize local variable D1 d1; // create object of class d1 D2 d2; // create object of class d2 d1.a = 5; // error, D1::a is private in class D1 d2.b = 10; // error, B::b is inherited private to // derived class D2 d2.c = 5; // valid, modified access from private to public d2.B::c = 5; // valid, public B::c d1.c = 5; // valid, B::c is inherited publicly d1.d = 5; // error, B::d is protected in base class d2.e = 10; // error, private D2::e d1.g(i); // error, g(int) is protected in base class d1.h(i); // valid d2.h(i); // valid } /************************************************************************ * Access rules for multiple base classes are described in Multiple Access. * ************************************************************************/ ═══ 14.4. Multiple Inheritance ═══ You can derive a class from more than one base class. Deriving a class from more than one direct base class is called multiple inheritance. In the following example, classes A, B, and C are direct base classes for the derived class X: class A { /* ... */ }; class B { /* ... */ }; class C { /* ... */ }; class X : public A, private B, public C { /* ... */ }; The order of derivation is relevant only to determine the order of default initialization by constructors and cleanup by destructors. For more information, see Initialization by Constructor. A direct base class cannot appear in the base list of a derived class more than once: class B1 { /* ... */ }; // direct base class class D : public B1, private B1 { /* ... */ }; // error However, a derived class can inherit an indirect base class more than once, as shown in the following example: class L { /* ... */ }; // indirect base class class B2 : public L { /* ... */ }; class B3 : public L { /* ... */ }; class D : public B2, public B3 { /* ... */ }; // valid In the above example, class D inherits the indirect base class L once through class B1 and once through class B2. However, this may lead to ambiguities because two objects of class L exist, and both are accessible through class D. You can avoid this ambiguity by referring to class L using a qualified class name, for example, B2::L or B3::L . You can also avoid this ambiguity by using the base specifier virtual to declare a base class. Examples of Single and Multiple Inheritance Related Information o Virtual Base Classes o Multiple Access o Inheritance Overview o Derivation o Initialization by Constructor o C++ Classes ═══ 14.4.1. Virtual Base Classes ═══ If you have an inheritance graph in which two or more derived classes have a common base class, you can use a virtual base class to ensure that the two classes share a single instance of the base class. In the following example, an object of class D has two distinct objects of class L, one through class B1 and another through class B2. You can use the keyword virtual in front of the base class specifiers in the base lists of classes B1 and B2 to indicate that only one class L, shared by class B1 and class B2, exists. For example: class L { /* ... */ }; // indirect base class class B1 : virtual public L { /* ... */ }; class B2 : virtual public L { /* ... */ }; class D : public B1, public B2 { /* ... */ }; // valid Using the keyword virtual in this example ensures that an object of class D inherits only one object of class L. A derived class can have both virtual and nonvirtual base classes. For example: class V { /* ... */ }; class B1 : virtual public V { /* ... */ }; class B2 : virtual public V { /* ... */ }; class B3 : public V { /* ... */ }; class D : public B1, public B2, public B3 { /* ... */ }; In the above example, class D has two objects of class V, one that is shared by classes B1 and B2 and one through class B3. Related Information o Multiple Inheritance o Multiple Access o Inheritance Overview o Derivation o C++ Classes ═══ 14.4.2. Multiple Access ═══ If you have an inheritance graph containing virtual base classes and a name can be reached through more than one path, the name is accessed through the path that gives the most access. For example: class L { public: void f(); }; class B1 : private virtual L { /* ... */ }; class B2 : public virtual L { /* ... */ }; class D : public B1, public B2 { public: void f() {L::f();} // L::f() is accessed through B2 // and is public }; In the above example, the function f() is accessed through class B2. Because class B2 is inherited publicly and class B1 is inherited privately, class B2 offers more access. An accessible base class is a publicly derived base class that is neither hidden nor ambiguous in the inheritance hierarchy. When you derive classes, ambiguities can result if base and derived classes have members with the same names. Access to a base class member is ambiguous if you use a name or qualified name that does not refer to a unique function, object, type, or enumerator. The declaration of a member with an ambiguous name in a derived class is not an error. The ambiguity is only flagged as an error if you use the ambiguous member name. For example, if two base classes have a member of the same name, an attempt to access the member by the derived class is ambiguous. You can resolve ambiguity by qualifying a member with its class name using the :: (scope resolution) operator. Example of Resolving Ambiguous Access The compiler checks for ambiguities at compile time. Because ambiguity checking occurs before access control or type checking, ambiguities may result even if only one of several members with the same name is accessible from the derived class. Conversions (either implicit or explicit) from a derived class pointer or reference to a base class pointer or reference must refer unambiguously to the same accessible base class object. For example: class W { /* ... */ }; class X : public W { /* ... */ }; class Y : public W { /* ... */ }; class Z : public X, public Y { /* ... */ }; void main () { Z z; X* xptr = &z; // valid Y* yptr = &z; // valid W* wptr = &z; // error, ambiguous reference to class W // X's W or Y's W ? } You can use virtual base classes to avoid ambiguous reference. For example: class W { /* ... */ }; class X : public virtual W { /* ... */ }; class Y : public virtual W { /* ... */ }; class Z : public X, public Y { /* ... */ }; void main () { Z z; X* xptr = &z; // valid Y* yptr = &z; // valid W* wptr = &z; // valid, W is virtual therefore only one // W subobject exists } Related Information o Virtual Base Classes o Multiple Inheritance o Scope Resolution Operator o Inheritance Overview o Derivation o Member Access ═══ Example of Resolving Ambiguous Access ═══ /************************************************************************ * The following example uses the :: (scope resolution) operator to resolve an ambiguous reference. * ************************************************************************/ class B1 { public: int i; int j; int g( ); }; class B2 { public: int j; int g( ); }; class D : public B1, public B2 { public: int i; }; void main () { D dobj; D *dptr = &dobj; dptr -> i = 5; // valid, D::i dptr -> j = 10; // error, ambiguous reference to j dptr->B1::j = 10; // valid, B1::j dobj.g( ); // error, ambiguous reference to g( ) dobj.B2::g( ); // valid, B2::g( ) } ═══ 14.5. Virtual Functions ═══ In C++, dynamic binding is supported by the mechanism of virtual functions. Virtual functions must be members of a class. Use virtual functions when you expect a class to be used as a base class in a derivation and when the implementation of the function may be overridden in the derived class. You can declare a member function with the keyword virtual in its class declaration. For example: class B { int a,b,c; public: virtual int f(); }; You can reimplement a virtual member function, like any member function, in any derived class. The implementation that is executed when you make a call to a virtual function depends on the type of the object for which it is called. If a virtual member function is called for a derived class object and the function is redefined in the derived class, the definition in the derived class is executed. In this case, the redefined derived class function is said to override the base class function. This occurs even if the access to the function is through a pointer or reference to the base class. If you call a virtual function with a pointer that has base class type but points to a derived class object, the member function of the derived class is called. However, if you call a nonvirtual function with a pointer that has base class type, the member function of the base class is called regardless of whether the pointer points to a derived class object. Example of Overriding Virtual Functions If the argument types or the number of arguments of the two functions are different, the functions are considered different, and the function in the derived class does not override the function in the base class. The function in the derived class hides the function in the base class. The return type of an overriding virtual function can differ from the return type of the overridden virtual function provided that: o The overridden function returns a pointer or a reference to a class T AND o The overriding virtual function returns a pointer or a reference to a class derived from T. An error does result when a virtual function that returns D* overrides an virtual function that returns B* where B is an ambiguous base class of D. The reason is that two or more instances of class B will exist within class D, and the compiler will not know which base B to return. For more information, see Return Values. A virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called. You can declare a virtual function to be a friend of another class. If a function is declared virtual in its base class, it can still be accessed directly using the :: (scope resolution) operator. In this case, the virtual function call mechanism is suppressed and the function implementation defined in the base class is used. In addition, if you do not redefine a virtual member function in a derived class, a call to that function uses the function implementation defined in the base class. A virtual function must be one of the following: o Defined o Declared pure o Defined and declared pure A base class containing one or more pure virtual member functions is called an abstract class. Related Information o Virtual Base Classes o Ambiguous Virtual Function Calls o Virtual Function Access o Abstract Classes o Return Values o Friends o Scope Resolution Operator o Inheritance Overview o Derivation ═══ Example of Overriding Virtual Functions ═══ /************************************************************************ * The following example shows how virtual functions can be redefined. * ************************************************************************/ class B { public: virtual int f(); virtual int g(); int h(); }; class D : public B { public: int f(); int g(char*); // hides B::g() int h(); }; void main () { D d; B* bptr = ─"─; bptr->f(); // calls D::f() because f() is virtual bptr->h(); // calls B::h() because h() is nonvirtual bptr->g(); // calls B::g() d.g(); // error, wrong number and type of arguments d.g("string"); // calls D::g(char*) } ═══ 14.5.1. Ambiguous Virtual Function Calls ═══ It is an error to override one virtual function with two or more ambiguous virtual functions. This can happen in a derived class that inherits from two nonvirtual bases that are derived from a virtual base class. Example of Ambiguous Virtual Functions A special case occurs when the ambiguous overriding virtual functions come from separate instances of the same class type. In the following example, there are two objects (instances) of class L. There are two data members L::count, one in class A and one in class B. If the declaration of class D is allowed, incrementing L::count in a call to L::f() with a pointer to class V is ambiguous. class V { public: virtual void f(); }; class L : virtual public V { int count; void f(); }; void L::f() {++count;} class A : public L { /* ... */ }; class B : public L { /* ... */ }; class D : public A, public B { /* ... */ }; // error void main () { D d; V* vptr = ─"─; vptr->f(); } In the above example, the function L::f() is expecting a pointer to an L object; that is, the this pointer for class L, as its first implicit argument. Because there are two objects of class L in a D object, there are two this pointers that could be passed to L::f(). Because the compiler cannot decide which this pointer to pass to L::f(), the declaration of class D is flagged as an error. Related Information o Virtual Functions o Virtual Function Access o Multiple Access o Scope Resolution Operator o Member Functions ═══ Example of Ambiguous Virtual Functions ═══ /************************************************************************ * The following example shows a class that inherits from two nonvirtual bases that are derived from a virtual base class. * ************************************************************************/ class V { public: virtual void f() { /* ... */ }; }; class A : virtual public V { void f() { /* ... */ }; }; class B : virtual public V { void f() { /* ... */ }; }; class D : public B { /* ... */ }; // error void main () { D d; V* vptr = ─"─; vptr->f(); // which f(), A::f() or B::f()? } /************************************************************************ * In class A, only A::f() will override V::f(). Similarly, in class B, only B::f() will override V::f(). However, in class D, both A::f() and B::f() will try to override V::f(). This attempt is not allowed because it is not possible to decide which function to call if a D object is referenced with a pointer to class V, as shown in the above example. Because only one function can override a virtual function, the compiler flags this situation as an error. * ************************************************************************/ ═══ 14.5.2. Virtual Function Access ═══ The access for a virtual function is specified when it is declared. The access rules for a virtual function are not affected by the access rules for the function that later overrides the virtual function. In general, the access of the overriding member function is not known. If a virtual function is called with a pointer or reference to a class object, the type of the class object is not used to determine the access of the virtual function. Instead, the type of the pointer or reference to the class object is used. In the following example, when the function f() is called using a pointer having type B*, bptr is used to determine the access to the function f(). Even though the definition of f() defined in class D is executed, the access of the member function f() in class B is used. When the function f() is called using a pointer having type D*, dptr is used to determine the access to the function f(). This call produces an error because f() is declared private in class D. class B { public: virtual void f(); }; class D : public B { private: void f(); }; void main () { D dobj; B *bptr = &dobj; D *dptr = &dobj; bptr->f(); // valid, virtual B::f() is public, // D::f() is called dptr->f(); // error, D::f() is private } Related Information o Virtual Functions o Ambiguous Virtual Function Calls o Inherited Member Access ═══ 14.6. Abstract Classes ═══ An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. Pure virtual functions are inherited. You can declare a function to be pure by using a pure specifier in the declaration of the member function in the class declaration. For example: class AB // abstract class { public: virtual void f()= 0; // pure virtual member function }; A function that is declared pure has no definition and cannot be executed. Because a pure virtual function has no implementation, any attempt to call that function is undefined. Such a call does not cause an error. No objects of an abstract class can be created. Note: Because destructors are not inherited, a virtual destructor that is declared pure must have a definition. Virtual member functions are inherited. If a base class contains a pure virtual member function and a class derived from that base class does not redefine that pure virtual member function, the derived class itself is an abstract class. Any attempt to create an object of the derived class type produces an error. Examples of Errors using Abstract Classes You cannot use an abstract class as the type of an explicit conversion, as an argument type, or as the return type for a function. You can declare a pointer or reference to an abstract class. Related Information o Virtual Functions o Inheritance Overview o Derivation o C++ Classes ═══ Examples of Errors using Abstract Classes ═══ /************************************************************************ * The following example shows an attempt to create an object of an abstract class type. * ************************************************************************/ class AB // abstract class { public: virtual void f()= 0; // pure virtual member function }; class D: public AB { public: void f(); }; void main () { D d; d.f() ; // calls D::f() AB ab; // error, cannot create an object of an // abstract class type } /************************************************************************ * The following example shows an attempt to create an object of a class derived from an abstract class, but that does not redefine the pure virtual function of that abstract class. * ************************************************************************/ For example: class AB // abstract class { public: virtual void f()= 0; // pure virtual member function }; class D2: public AB { int a,b,c; public: void g(); }; void main () { D2 d; // error, cannot declare an object of abstract class D2 } To avoid the error in the above example, provide a declaration of D2::f(). ═══ 15. Templates ═══ This chapter describes the C++ template facility. A template specifies how an individual class or function can be constructed by providing a blueprint description of classes or functions within the template. Unlike an ordinary class or function definition, a template definition contains the template keyword, and uses a type argument, instead of a type, in one or more of the constructs used to define the class or function template. Individual classes or functions can then be generated simply by specifying the template name and by naming the type for the particular class or function as the type argument of the template. You can use templates to define a family of types or functions. The following topics are described in this chapter: o Template Syntax o Structuring Your Program Using Templates o Class Templates o Function Templates o Differences between Class and Function Templates o Member Function Templates o Friends and Templates o Static Data Members and Templates Important When you link C++ object files, you must use the icc command with the /Tdp option to invoke the linker. If you invoke the linker in a separate step (with the LINK386 command), the template functions may not resolve correctly. Refer to the IBM C/C++ Tools: Programming Guide for programming hints on using templates in C++ programs. Related Information o C++ Classes o Functions o Types ═══ 15.1. Template Syntax ═══ The syntax for a template is: ┌────────────────────────┐ >>──template──┐──┴┬─argument-declaration─┬┴──>────────────────────────────────>< │ │ │ └─type──identifier─────┘ The declaration in a template declaration must define or declare one of the following: o A class o A function o A static member of a template class The identifier of a type is defined to be a type-name in the scope of the template declaration. A template declaration can appear as a global declaration only. The template arguments (within the < and > delimitiers) specify the types and the constants within the template that must be specified when the template is instantiated. Examples of Templates Default intializers are permitted in template arguments, under the following conditions: o They can only be applied to nontype template arguments. o Like functions, they can only be applied to trailing arguments. o Subsequent template declarations can add default initializers but cannot redefine existing default initializers. o They can only be applied to class template declarations, not to function template declarations. Note: A template that defines a member function of a class template is treated as a function template. Such a template cannot have default intializers. Example of Default Initializers in Templates Related Information o Structuring Your Program Using Templates o Class Templates o Function Templates o C++ Classes o Functions o Static Members ═══ Examples of Templates ═══ Given the following template: template class Key { L k; L* kptr; int length; public: Key(L); // ... }; The following table shows what the classes Key, Key, and Key look like: ┌─────────────────────────┬──────────────────────────┬─────────────────────────┐ │ class Key i; │ class Key c; │ class Key m; │ ├─────────────────────────┼──────────────────────────┼─────────────────────────┤ │ class Key { │ class Key { │ class Key { │ │ int k; │ char* k; │ mytype k; │ │ int * kptr; │ char** kptr; │ mytype* kptr; │ │ int length; │ int length; │ int length; │ │ public: │ public: │ public: │ │ Key(int); │ Key(char*); │ Key(mytype); │ │ // ... }; │ // ... }; │ // ... }; │ └─────────────────────────┴──────────────────────────┴─────────────────────────┘ The above declarations create the following objects: o i of type Key o c of type Key o m of type Key Note that the three classes above have different names. The types contained within the angle braces are not arguments to the class names, but part of the class names themselves. Key and Key are class names. Within the context of the above example, a class called Key (with no template argument list) is undefined. ═══ Example of Default Initializers in Templates ═══ /************************************************************************ * The following example shows a valid template declaration with default initializers: * ************************************************************************/ #include template class X } public: T s; X(int j=4); int val(T&) } return i; {; {; template X::X(int j):s(i)} printf("i=%d j=%d\n",i,j); { void main() } X myX(2); X myX2(4); { ═══ 15.2. Structuring Your Program Using Templates ═══ There are three ways to structure your program using templates: 1. Include the function template definition (both the .h and .c files) in all files that may reference the corresponding template functions. 2. Include the function template declaration (the .h file only) in all files that may reference the corresponding template functions, but include the function definition (both the .h and .c files) in one file only. 3. Include the declaration of the function templates in a header file and the definition in a source file that has the same name. When you include the header file in your source, the compiler automatically generates the template functions. Use the /Ft+ option to enable this method. The following examples illustrate all three methods using two files: stack.h and stackdef.h To instantiate a stack of 50 ints, you would declare the following in each source file that requires it: stack intStack(50); For method 1, each source file using the template should include both stack.h and stackdef.h. For method 2, every source file should include stack.h, but only one of the files needs to include stackdef.h. For method 3, every source file should include stack.h. The compiler automatically generates the template functions in the TEMPINC subdirectory that is created in the current directory. To use this method, copy stackdef.h to stack.c and use the /Ft+ option, which is the default. Important When you link C++ object files, you must use the icc command with the /Tdp option to invoke the linker. If you invoke the linker in a separate step (with the LINK386 command), the template functions might not resolve correctly. Related Information o Template Syntax o Class Templates o Function Templates o Differences between Class and Function Templates o "Using Templates in C++ Programs" in the Programming Guide. ═══ stack.h and stackdef.h ═══ /************************************************************************ * stack.h * ************************************************************************/ #ifndef _STACK_TPL_H #define _STACK_TPL_H template class stack { private: T* v; T* p; int sz; public: stack( int ); ~stack(); void push( T ); }; #endif /************************************************************************ * stackdef.h * ************************************************************************/ #include "stack.h" template stack::stack( int s ) { v = p = new T[sz=s]; } template stack::~stack() { delete [] v; } template void stack::push( T a ) { *p++ = a; } ═══ 15.3. Class Templates ═══ The relationship between a class template and an individual class is like the relationship between a class and an individual object. An individual class defines how a group of objects can be constructed, while a class template defines how a group of classes can be generated. A template definition is identical to any valid class definition that the template might generate, except for the following: o The class template definition is preceded by template < template-argument-list > where template-argument-list can include zero or more arguments of user-defined type and zero or more argument declarations. The template-argument-list must contain at least one argument. o Types, variables, constants and objects within the class template can be declared with arguments of user-defined type as well as with explicit types (for example, int or char). o The template-argument-list can include argument-declarations (for example,int a or char* b), which are generally used to define constant values within the created class. A class template can declare a class without defining it by using an elaborated type specifier. For example: template class key; This reserves the name as a class template name. All template declarations for a class template must have the same types and number of template arguments. Only one template declaration containing the class definition is allowed. Note the distinction between the terms class template and template class: Class template is a template used to generate template classes. A class template can be only a declaration, or it can be a definition of the class. Template class is an instance of a class template. You can instantiate the class template by declaring a template class. If the definitions of the member functions of the template class are not inlined, then you have to define them. When you instantiate a template class, its argument list must match the argument list in the class template declaration. Syntax of a Template Class Instantiation Note: When you have nested template argument lists, you must have a separating space between the > at the end of the inner list and the one at the end of the outer list. Otherwise, there is an ambiguity between the output operator >> and two template list delimiters >. template class key { // ... }; template class vector { // ... }; void main () { class key >; // instantiate template } Objects and functions of individual template classes can be accessed by any of the techniques used to access ordinary class member objects and functions. Examples of Accessing Class Template Members Related Information o Class Template Declarations and Definitions o Nontype Template Arguments o Explicitly Defined Template Classes o Function Templates o Template Syntax o Structuring Your Program Using Templates o C++ Classes o Differences between Class and Function Templates ═══ Syntax of a Template Class Instantiation ═══ The syntax for instantiation of a template class is: ┌─,───────────────────────┐ >>──template-name──┐──┴┬─type──────────────────┬┴──>──>< │ │ │ └─assignment-expression─┘ ═══ Examples of Accessing Class Template Members ═══ Given a class template: template class vehicle { public: vehicle() { /* ... */ } // constructor ~vehicle() {}; // destructor T kind[16]; T* drive(); static void roadmap(); // ... }; and the declaration: vehicle bicycle; // instantiates the template the constructor, the constructed object, and the member function drive() can be accessed with any of the following (assuming the standard header file is included in the program file): ┌───────────────────────────────┬──────────────────────────────────────────────┐ │ constructor │ "vehicle bicycle; │ │ │ // constructor called automatically │ │ │ // object bicycle created" │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ object "bicycle" │ "strcpy (bicycle.kind, "10 speed"); │ │ │ bicycle.kind[0] = '2';" │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ function "drive()" │ "char* n = bicycle.drive();" │ ├───────────────────────────────┼──────────────────────────────────────────────┤ │ function "roadmap()" │ "vehicle::roadmap();" │ └───────────────────────────────┴──────────────────────────────────────────────┘ ═══ 15.3.1. Class Template Declarations and Definitions ═══ A class template must be declared before any declaration of a corresponding template class. A class template definition can only appear once in any single compilation unit. A class template must be defined before any use of a template class that requires the size of the class or refers to members of the class. In the following example, the class template key is declared before it is defined. The declaration of the pointer keyiptr is valid because the size of the class is not needed. The declaration of keyi, however, causes an error. template class key; // class template declared, // not defined yet // class key *keyiptr; // declaration of pointer // class key keyi; // error, cannot declare keyi // without knowing size // template class key; // now class template defined { // ... }; If a template class is used before the corresponding class template is defined, the compiler issues an error. A class name with the appearance of a template class name is considered to be a template class. In other words, angle brackets are valid in a class name only if that class is a template class. The definition of a class template is not compiled until the definition of a template class is required. At that point, the class template definition is compiled using the argument list of the template class to instantiate the template arguments. Any errors in the class definition are flagged at this time. If the definition of a class template is never required, it is not compiled. In this case, some errors in the definition might not be flagged by the compiler. The /Wcls option can be used to find possible errors in class templates that are not compiled. A class template can only be defined once within a compilation unit, and the class template name cannot be declared to refer to any other template, class, object, function, value, or type in the same scope. Related Information o Class Templates o Nontype Template Arguments o Explicitly Defined Template Classes o Using the /Wgrp Diagnostic Options o C++ Classes o Function Templates o Differences between Class and Function Templates ═══ 15.3.2. Nontype Template Arguments ═══ A nontype template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members. Nontype template arguments are normally used to initialize a class or to specify the sizes of class members. For nontype integral arguments, the instance argument matches the corresponding template argument as long as the instance argument has a value and sign appropriate to the argument type. For nontype address arguments, the type of the instance argument must be of the form identifier or &identifier, and the type of the instance argument must match the template argument exactly, except that a function name is changed to a pointer to function type before matching. The resulting values of nontype template arguments within a template argument list form part of the template class's type. If two template class names have the same template name and if their arguments have identical values, they are the same class. Example of Nontype Template Arguments Note: Arguments that contain the < symbol or the > symbol must be enclosed in parentheses to prevent it from being parsed as the template argument list delimiter when it is being used as a relational operator or a nested template delimiter. For example, the arguments in the following definition are valid: myfilebuf10)> x; // valid The following definition, however, is not valid because the greater than operator (>) is interpreted as the closing delimiter of the template argument list: myfilebuf10> x; // error If the template arguments do not evaluate identically, the objects created are of different types: myfilebuf x; // create object x of class // myfilebuf myfilebuf y; // error, 200.0 is a double, // not an int The instantiation of y fails because the value 200.0 is of type double, and the template argument is of type int. The following two objects: myfilebuf x myfilebuf y belong to separate template classes, and referencing either of these objects later with myfilebuf is an error. A class template does not need to have a type argument if it has nontype arguments. For example, the following template is a valid class template: template class C { public: int k; C() { k = i; } }; This class template can be instantiated by declarations such as: class C<100>; class C<200>; Again, these two declarations refer to distinct classes because the values of their nontype arguments differ. Related Information o Class Templates o Class Template Declarations and Definitions o Explicitly Defined Template Classes o C++ Classes o Function Templates o Differences between Class and Function Templates ═══ Example of Nontype Template Arguments ═══ In the following example, a class template is defined that requires a nontype template int argument as well as the type argument: template class myfilebuf { T* filepos; static int array[size]; public: myfilebuf() { /* ... */ } ~myfilebuf(); advance(); // function defined elsewhere in program }; In the example above, the template argument size becomes a part of the template class name. An object of such a template class is created with both the type arguments of the class and the values of any additional template arguments. An object x, and its corresponding template class with arguments double and size=200, can be created from this template with a value as its second template argument: myfilebuf x; x can also be created using an arithmetic expression: myfilebuf x; The objects created by these expressions are identical because the template arguments evaluate identically. The value 200 in the first expression above could have been represented by an expression whose result at compile time is known to be equal to 200, as shown in the second construction. ═══ 15.3.3. Explicitly Defined Template Classes ═══ You can override the definition of a class template of a particular template class by providing a class definition for the type of class required. For example, the following class template creates a class for each type for which it is referenced, but that class may be inappropriate for a particular type: template class portfolio { double capital; M arr; // ... } ; The type for which the template class is inappropriate can be defined by using the applicable template class name. Assuming the inappropriately defined type is stocks, you can redefine the class portfolio as follows: class portfolio { double capital; stocks yield; // ... }; This explicit definition must be seen before the template class is referenced. In particular, a template class such as portfolio cannot be defined unless its class template has also been defined. Related Information o Class Templates o Class Template Declarations and Definitions o Nontype Template Arguments o C++ Classes o Function Templates o Differences between Class and Function Templates ═══ 15.4. Function Templates ═══ A function template allows you to define a group of functions that are the same except for the types of one or more of their arguments or objects. All type arguments in a function template must be used in the argument list or in the class qualifier for the function name. The type of a template function argument need not be explicitly specified when the template function is called. In this respect, a template function differs from a template class. Example of a Function Template Note the distinction between the terms function template and template function: Function template is a template used to generate template functions. A function template can be only a declaration, or it can define the function. Template function is a function generated by a function template. Because template functions can be generated in all compilation units that contain function template definitions, you may want to group function template definitions into one or two compilation units. Using templates in C++ programs is described completely in the IBM C/C++ Tools: Programming Guide. Related Information o Overloading Resolution for Template Functions o Explicitly Defined Template Functions o Function Template Declarations and Definitions o Differences between Class and Function Templates o Functions o Class Templates ═══ Example of a Function Template ═══ If you want to create a function approximate(), which determines whether two values are within 5% of each other, you can define the following template: #include template int approximate (T first, T second) { double aptemp=double(first)/double(second); return int(abs(aptemp-1.0) <= .05); }; Assuming you have two values of type float you want to compare, you can use the approximate function template: float a=3.24, b=3.35; if (approximate(a,b)) cout << "a and b are pretty close" << endl; A template function int approximate(float,float) is generated to resolve the call. ═══ 15.4.1. Overloading Resolution for Template Functions ═══ Resolution of overloaded template functions is done in the following order: 1. Look for a function with an exact type match. This does not include template functions, unless such functions were explicitly declared using a function declaration. Trivial conversions are performed if they produce an exact type match. 2. Look for a function template that allows generation of a function with an exact type match. Trivial conversions are performed if they produce an exact type match. 3. Try ordinary overloading resolution for functions already present. This does not include template functions, unless such functions were explicitly declared using a function declaration. A call to a template function causes an error, and no overloading is done if the following conditions are true: o The only available functions for a call are template functions. o These functions would require nontrivial conversions for the call to succeed. o These functions have not been explicitly declared. Example of Overloading a Template Function Related Information o Trivial Conversions o Conversions o Function Templates o Explicitly Defined Template Functions o Function Template Declarations and Definitions o Functions o Differences between Class and Function Templates o Class Templates ═══ Example of Overloading a Template Function ═══ In the case of the approximate() function template: #include template int approximate (T first, T second) { double aptemp=double(first)/double(second); return int(abs(aptemp-1.0) <= .05); }; if the two input values are of different types, overloading resolution does not take place: float a=3.24; double b=3.35; if (approximate(a,b)) // error, different types { /* ... */ } The solution is to force a conversion to one of the available function types by explicitly declaring the function for the chosen type. To resolve the float/double example above, include the following function declaration: int approximate(double a, double b); // force conversion of the float to double This declaration creates a function approximate() that expects two arguments of type double, so that when approximate(a,b) is called, the overloading is resolved by converting variable a to type double. ═══ 15.4.2. Explicitly Defined Template Functions ═══ In some situations, a function template can define a group of functions in which, for one function type, the function definition would be inappropriate. For instance, the function template: template int approximate(T first, T second); determines whether two values are within 5% of each other. The algorithm used for this function template is appropriate for numerical values, but for char* values, it would indicate whether the pointers to two character strings are within 5% of one another, not whether the strings themselves are approximately equal. Whether two pointers are within 5% of each other is not useful information. You can define an explicit template function for char* values to compare the two strings themselves, character by character. Example of an Explicitly Defined Template Function Explicit definition has the same effect on template overloading resolution as explicit declaration (See Overloading Resolution for Template Functions for more information.) If a template function is explicitly defined for: int approximate(double a, double b) { /* ... */ } then a call of: double a=3.54; float b=3.5; approximate(a,b); resolves in a call to approximate(double a, double b) and variable b is converted to type double. Related Information o Function Templates o Overloading Resolution for Template Functions o Function Template Declarations and Definitions o Functions o Differences between Class and Function Templates o Class Templates ═══ Example of an Explicitly Defined Template Function ═══ The following explicitly defined template function compares two strings and returns a value indicating whether more than 5% of the characters differ between the two strings: #include int approximate(char *first, char *second) { if (strcmp(first,second) == 0) return 1; // strings are identical double difct=0; int maxlen=0; if (strlen(first)>strlen(second)) maxlen=strlen(first); else maxlen=strlen(second); for (int i=0; i<=maxlen ; ++i) if ( first[i] != second[i] ) difct++; return int((difct / maxlen) <= .05 ); } Given this definition, the function call: approximate("String A","String B"); invokes the explicitly defined function above, and no template function is generated. ═══ 15.4.3. Function Template Declarations and Definitions ═══ When a template function is defined explicitly within a compilation unit, this definition is used in preference to any instantiation from the function template. For example, if one compilation unit contains the code: #include template T f(T i) {return i+1;} void main() { cout << f(2) << endl; } and another contains: int f(int i) {return i+2;} when compiled and run, the program prints the number 4 to standard output, indicating that the explicitly defined function was used to resolve the call to f(). Each template, whether of a class or of a function, must be defined at most once within a compilation unit. The same applies to an explicitly defined template class or function. Function templates and class templates can be declared many times. A template class is considered declared if its name is used. A template function is considered declared if any of the following applies: o A function whose name matches a function template's name is declared, and an appropriate template function can be generated. o A function whose name matches a function template's name is called, and an appropriate template function can be generated. o A function whose name matches a function template's name is called, and the template function has been explicitly defined. o The address of a template function is taken in such a way that instantiation can occur. This means the pointer to function must supply a return type and argument types that can be used to instantiate the template function. A template function is instantiated or generated if the function is referenced in any of the following ways, provided that function is not explicitly defined elsewhere in the program: o The function is declared. o A call to the function is made. o The address of the function is taken. When a template function is instantiated, the body of the function template is compiled using the template-arg-list of the template class to instantiate the template arguments. Any errors in the function definition are flagged at this time. If a template function is never generated from a function template, it is not compiled. In this case, some errors in the function definition might not be flagged by the compiler. Related Information o Function Templates o Overloading Resolution for Template Functions o Explicitly Defined Template Functions o Functions o Differences between Class and Function Templates o Class Templates ═══ 15.5. Differences between Class and Function Templates ═══ The name of a template class is a compound name consisting of the template name and the full template argument list enclosed in angle braces. Any references to a template class must use this complete name. For example: template class ex { T a; int r; // ... }; //... ex obj1; // valid ex obj2; // error ex obj3; // error C++ requires this explicit naming convention to ensure that the appropriate class can be generated. A template function, on the other hand, has the name of its function template and the particular function chosen to resolve a given template function call is determined by the type of the calling arguments. In the following example, the call min(a,b) is effectively a call to min(int a, int b), and the call min(af, bf) is effectively a call to min(float a, float b): template T min(T a, T b) { if (a < b) return a; else return b; } void main() { int a = 0; int b = 2; float af = 3.1; float bf = 2.9; cout << "Here is the smaller int " << min(a,b) << endl; cout << "Here is the smaller float " << min(af, bf) << endl; } Related Information o Class Templates o Function Templates o C++ Classes o Functions ═══ 15.6. Member Function Templates ═══ In Function Templates, a function template was defined outside of any template class. However, functions in C++ are often member functions of a class. If you want to create a class template and a set of function templates to go with that class template, you do not have to create the function templates explicitly, as long as the function definitions are contained within the class template. Any member function (inlined or noninlined) declared within a class template is implicitly a function template. When a template class is declared, it implicitly generates template functions for each function defined in the class template. There are three ways to define template member functions: 1. Explicitly at file scope for each type used to instantiate the template class. 2. At file scope with the template-arguments. 3. Inlined in the class template itself. Examples of Defining Template Member Functions Member function templates are used to instantiate any functions that are not explicitly generated. If you have both a member function template and an explicit definition, the explicit definition is used. The template argument is not used in a constructor name. For example: template class Key { Key(); // default constructor Key( L ); // constructor taking L by value Key( L ); // error, implicit within class template }; The declaration Key(L) is an error because the constructor does not use the template argument. Assuming the above class template was corrected by removing the offending line, you can define a function template for the class template's constructor: // Constructor contained in function template: template Key::Key(int) { /* ... */ } // valid, constructor template argument assumed template Key::Key(int) { /* ... */ } /* error, constructor template argument implicit in class template argument */ A template function name does not include the template argument. The template argument does, however, appear in the template class name if a member function of a template class is defined or declared outside of the class template. The definition: Key::Key(int) { /* ... */ } is valid because Key (with template argument) refers to the class, while Key(int) { /* ... */ } refers to the member function. Related Information o Class Templates o Function Templates o C++ Class Members and Friends ═══ Examples of Defining Template Member Functions ═══ /************************************************************************ * The following three examples illustrate the three ways to define template member functions: Method 1 * ************************************************************************/ template class key { public: void f(T); }; void key::f(char) { /* ... */ } void key::f(int ) { /* ... */ } void main() { int i = 9; key< int> keyobj; keyobj.f(i); } /************************************************************************ * Method 2 * ************************************************************************/ template class key { public: void f(T); }; template void key ::f(T) { /* ... */ } void main() { int i = 9; key< int> keyobj; keyobj.f(i); } /************************************************************************ * Method 3 * ************************************************************************/ template class key { public: void f(T) { /* ... */ } }; void main() { int i = 9; key< int> keyobj; keyobj.f(i); } ═══ 15.7. Friends and Templates ═══ A friend function can be declared in a class template either as a single function shared by all classes created by the template or as a template function that varies from class to class within the class template. For example: template class portfolio { //... friend void taxes(); friend void transact(T); friend portfolio* invest(portfolio*); friend portfolio* divest(portfolio*); //error // ... }; In this example, each declaration has the following characteristics: taxes() is a single function that can access private and protected members of any template class generated by the class template. Note that taxes() is not a template function. transact(T) is a function template that declares a distinct function for each class generated by the class template. The only private and protected members that can be accessed by functions generated from this template are the private and protected members of their template class. invest(portfolio*) is a function template whose return and argument types are pointers to objects of type portfolio. Each class generated by the class template will have a friend function of this name, and each such function will have a pointer to an object of its own class as both its return type and its argument type. divest(portfolio*) is an error because portfolio* attempts to point to a class template. A pointer to a class template is undefined and produces an error. This statement can be corrected by using the syntax of the invest() function template instead. Because all friend functions in this example are declared but not defined, you could create a set of function templates to define those functions that are implicitly template functions (that is, all the valid functions except taxes()). The function templates would then be used to instantiate the template functions as required. Related Information o Friends o Class Templates o Function Templates o C++ Classes o Functions ═══ 15.8. Static Data Members and Templates ═══ A static declaration within a class template declares a static data member for each template class generated from the template. The static declaration can be of type template-argument or of any defined type. Like cplr437'.member function templates, you can explicitly define a static data member of a template class at file scope for each type used to instantiate a template class. For example: template class key { public: static T x; }; int key::x; char key::x; void main() { key::x = 0; } You can also define a static data member of a template class using a template definition at file scope. For example: template class key { public: static T x; }; template T key ::x; // template definition void main() { key::x = 0; } When you instantiate a template class, you must have either an explicit definition or a template definition for each static data member, but not both. Example of Static Data Members in Templates Related Information o Static Members o Class Templates o Explicitly Defined Template Classes o Function Templates o Explicitly Defined Template Functions ═══ Example of Static Data Members in Templates ═══ In the following example: template class Key { static L k; static L* kptr; static int length; // ... } The definitions of static variables and objects must be instantiated at file scope. If the classes Key and Key are instantiated from the above template, and no template definitions exist, the following static data members must be explicitly defined at file scope, or an error occurs: int Key::k, Key::length, Key::length; int* Key::kptr; double Key::k; double* Key::kptr = 0; ═══ 16. Exception Handling ═══ This chapter describes the C/C++ Tools implementation of C++ exception handling and discusses: o Formal and Informal Exception Handling o Using Exception Handling o Transferring Control o Constructors and Destructors in Exception Handling o Exception Specifications o unexpected() and terminate() Functions Note: C++ exception handling is not the same as OS/2 exception handling. A C++ exception exists only within the C++ language. An OS/2 exception is generated by the operating system, and can be used by the C/C++ Tools library to generate a signal. In this section, the term exception refers to a C++ exception. OS/2 exception handling is described in detail in the IBM C/C++ Tools: Programming Guide. ═══ 16.1. C++ Exception Handling Overview ═══ Exception handling provides a way for a function that encounters an unusual situation to throw an exception and pass control to a direct or indirect caller of that function. The caller may or may not be able to handle the exception. Code that intercepts an exception is called a handler. Regardless of whether or not the caller can handle an exception, it may rethrow the exception so it can be intercepted by another handler. C++ provides three language constructs to implement exception handling: o Try blocks o Catch blocks o Throw expressions Within a function, any unusual situation can be flagged with a throw expression. Your program can throw an object to pass information back to the caller. Any object can be thrown, including the object that caused the exception or an object constructed when the exception occurred. A call to a function that may throw an exception should be enclosed within a try statement. If the called function throws an exception and an exception handler is defined to catch the type of the object thrown, the exception handler is executed. In C++, a catch block implements an exception handler. A catch block follows immediately after a try statement or immediately after another catch block. A catch block includes a parenthesized exception declaration containing optional qualifiers, a type, and an optional variable name. The declaration specifies the type of object that the exception handler may catch. Once an exception is caught, the body of the catch block is executed. If a function throws an exception that cannot be caught, the program is terminated. Exception handling is not strictly synonymous with error handling, because the implementation allows the passing of an exception whether or not an error actually occurred. You can use exception handlers for things other than handling errors. For example, you can transfer control back to the original caller of a function. You might use this if you wanted to process the Quit key in a program and transfer control back to the driver program when the user types Quit. To do this exception handlers could be used to throw an object back to the driver. Note: C++ exception handling is not the same as OS/2 exception handling. A C++ exception exists only within the C++ language. An OS/2 exception is generated by the operating system, and can be used by the C/C++ Tools library to generate a signal. In this section, the term exception refers to a C++ exception. OS/2 exception handling is described in detail in the IBM C/C++ Tools: Programming Guide. Related Information o Formal and Informal Exception Handling o Using Exception Handling o Transferring Control ═══ 16.2. Formal and Informal Exception Handling ═══ While the exception handling features of C++ offer a formal mechanism for handling exceptions (language implemented), in many situations informal exception handling (logic implemented) is more appropriate. Generally speaking, formal exception handling should be implemented in libraries, classes, and functions likely to be accessed by several programs or programmers. It should also be used in classes and functions that are repeatedly accessed within a program but are not well-suited to handling their exceptions themselves. Because formal exception handling is designed for exceptional circumstances, it is not guaranteed to be efficient. Program performance is usually not affected when you do not invoke formal exception handling, although it can inhibit some optimizations. Informal exception handling, in which the user defines the appropriate action if an error or exception occurs, is often more suitable for handling errors. For example, a simple error, such as a user entering incorrect input, can more easily and clearly be handled by testing the input for validity and by requesting the input again if the original input is incorrect. Related Information o C++ Exception Handling Overview o Using Exception Handling o Transferring Control ═══ 16.3. Using Exception Handling ═══ The three keywords designed for exception handling in C++ are try, catch, and throw. Syntax of Exception Handling Keywords The steps required to implement an exception handler are: 1. Functions that are expected to be used by many programs are coded so that, when an error is detected, an exception is thrown. The throw expression generally throws an object. It may be created explicitly for purposes of exception handling, or it may be the object that caused the error to be detected. 2. Exceptions are anticipated in a caller by means of a try statement. Function calls that you anticipate might produce an exception can be enclosed in braces and preceded by the keyword try. 3. Immediately following the try block, you can code one or more catch blocks. Each catch block identifies what type or class of objects it can catch: a. If the object thrown matches the type of a catch expression, control passes to that catch block. b. If the object thrown does not match the first catch block, subsequent catch blocks are searched for a matching type. c. If no match is found, the search continues in all enclosing try blocks and then in the caller of the current function. d. If no match is found after all try blocks are searched, a call to terminate() is made, and the program is terminated normally. For information on the default handlers of uncaught exceptions, see unexpected() and terminate() Functions. Notes: o Any object can be thrown if it can be copied and destroyed in the function from which the throw occurs. o Exceptions should never be thrown from a C language signal handler. The result is undefined, and can cause program termination. A catch argument causes an error if it is a value argument, and a copy of it cannot be generated. Similarly, a throw expression causes an error if a copy of the value of the expression being thrown cannot be generated. Example of an Illegal catch Argument Related Information o C++ Exception Handling Overview o Formal and Informal Exception Handling o Transferring Control o Exception Specifications o unexpected() and terminate() Functions ═══ Syntax of Exception Handling Keywords ═══ The syntax for the try and catch keywords is: ┌───────────┐  │ >>──try──{────statement─┴──}──catch──(──> ┌───────────┐  │ >──┬─. . .───────────────────────────────────────┬──)──{────statement─┴──}──>< │ ┌────────────────┐ │ │  │ │ └───type-specifier─┴──┬─────────────────────┬─┘ ├─declarator──────────┤ └─abstract-declarator─┘ The syntax for the throw keyword is: >>──throw──┬───────────────────────┬──>< └─assignment-expression─┘ ═══ Example of an Illegal catch Argument ═══ A catch argument causes an error if it is a value argument, and a copy of it cannot be generated. For example: class B { public: B(); B(B&); }; // the following catch block will cause an error // catch(const B x) { // ... } The catch block causes an error because the compiler does not know the type of the object thrown at compile time. It assumes that the type of the thrown object is the same as the type of the catch argument. In the above example, the thrown object is assumed to be of type const B. The compiler uses a copy constructor on the thrown argument to create the catch argument. Because there is no copy constructor for class B that accepts const B as an input argument, the compiler cannot to perform the construction and an error occurs. ═══ 16.4. Transferring Control ═══ C++ implements the termination model of exception handling. In the termination model, when an exception is thrown, control never returns to the throw point. The throw point is the point in program execution where the exception occurred. C++ exception handling does not implement the resumption model of exception handling, which allows an exception handler to correct the exception and then return to the throw point. When an exception is thrown, control is passed out of the throw expression and out of the try block that anticipated the exception. Control is passed to the catch block whose exception type matches the object thrown. The catch block handles the exception as appropriate. If the catch block ends normally, the flow of control passes over all subsequent catch blocks. When an exception is not thrown from within a try block, the flow of control continues normally through the block, and passes over all catch blocks following the try block. An exception handler cannot return control to the source of the error by using the return statement. A return issued in this context returns from the function containing the catch block. If an exception is thrown and no try block is active, or if a try block is active and no catch block exception declaration matches the object thrown, a call to terminate() is issued. A call to terminate() in turn calls abort() to terminate the program. The abort() C library function is defined in the standard header file . Example of Basic Exception Handling Related Information o Catching Exceptions o Nested try Blocks o Rethrowing an Exception o Using a Conditional Expression in a Throw Expression o C++ Exception Handling Overview o Using Exception Handling o Exception Specifications o unexpected() and terminate() Functions o abort - Stop a Program o return ═══ Example of Basic Exception Handling ═══ /************************************************************************ * The following example illustrates the basic use of try, catch, and throw. The program prompts for a numerical user input and determines the input's reciprocal. Before it attempts to print the reciprocal to standard output, it checks that the input value is nonzero, to avoid a division by zero. If the input is zero, an exception is thrown, and the catch block catches the exception. If the input is nonzero, the reciprocal is printed to standard output. * ************************************************************************/ #include #include class IsZero { /* ... */ }; void ZeroCheck( int i ) { if (i==0) throw IsZero(); } void main() { double a; cout << "Enter a number: "; cin >> a; try { ZeroCheck( a ); cout << "Reciprocal is " << 1.0/a << endl; } catch ( IsZero ) { cout << "Zero input is not valid" << endl; exit(1); } exit(0); } /************************************************************************ * This example could have been coded more efficiently by using informal exception handling. However, it provides a simple illustration of formal exception handling. * ************************************************************************/ ═══ 16.4.1. Catching Exceptions ═══ You can declare a handler to catch many types of exceptions. The allowable objects that a function can catch are declared in the parentheses following the catch keyword (the catch argument). You can catch objects of the fundamental types, base and derived class objects, references, and pointers to all of these types. You can also catch const and volatile types. You can also use the catch(...) form of the handler to catch all thrown exceptions that have not been caught by a previous catch block. The ellipsis in the catch argument indicates that any exception thrown can be handled by this handler. If an exception is caught by a catch(...) block, there is no direct way to access the object thrown. Information about an exception caught by catch(...) is very limited. You can declare an optional variable name if you want to access the thrown object in the catch block. A catch block can only catch accessible objects. The object caught must have an accessible copy constructor. For more information on access, see Member Access; on copy constructors, see Copy by Initialization. An argument in the catch argument of a handler will match an argument in the expression of the throw expression (throw argument) if any of the following conditions is met: o The catch argument type matches the type of the thrown object. o The catch argument is a public base class of the thrown class object. o The catch specifies a pointer type, and the thrown object is a pointer type that can be converted to the pointer type of the catch argument by standard pointer conversion. Pointer conversion is described on page -- Reference cplr071 not found --.. Note: If the type of the thrown object is const or volatile, the catch argument must also be a const or volatile for a match to occur. However, a const, volatile, or reference type catch argument can match a nonconstant, nonvolatile, or nonreference object type. A nonreference catch argument type will match a reference to an object of the same type. Always place a catch block that catches a derived class before a catch block that catches the base class of that derived class (following a try block). If a catch block for objects of a base class is followed by a catch block for objects of a derived class of that base class, the latter block is flagged as an error. A catch block of the form catch(...) must be the last catch block following a try block or an error occurs. This placement ensures that the catch(...) block does not prevent more specific catch blocks from catching exceptions intended for them. Related Information o C++ Exception Handling Overview o Using Exception Handling o Transferring Control o Exception Specifications o volatile and const Qualifiers o Nested try Blocks o Rethrowing an Exception ═══ 16.4.2. Nested try Blocks ═══ When try blocks are nested and a throw occurs in a function called by an inner try block, control is transferred outward through the nested try blocks until the first catch block is found whose argument matches the argument of the throw expression. For example: try { func1(); try { func2(); } catch (spec_err) { /* ... */ } func3(); } catch (type_err) { /* ... */ } // if no throw is issued, control resumes here. In the above example, if spec_err is thrown within the inner try block (in this case, from func2()), the exception is caught by the inner catch block, and, assuming this catch block does not transfer control, func3() is called. If spec_err is thrown after the inner try block (for instance, by func3()), it is not caught and the function terminate() is called. If the exception thrown from func2() in the inner try block is type_err, the program will skip out of both try blocks to the second catch block without invoking func3(), because no appropriate catch block exists following the inner try block. If the entire try block in the example is in a function that has a throw list and does not include spec_err on its throw list, unexpected() is called. You can also nest a try block within a catch block. Related Information o Catching Exceptions o Transferring Control o Using Exception Handling o Rethrowing an Exception o Exception Specifications o unexpected() and terminate() Functions ═══ 16.4.3. Rethrowing an Exception ═══ If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression (throw with no argument) causes the originally thrown object to be rethrown. Because the exception has already been caught at the scope in which the rethrow expression occurs, it is rethrown out to the next dynamically enclosing try block. Therefore, it cannot be handled by catch blocks at the scope in which the rethrow expression occurred. Any catch blocks following the dynamically enclosing try block have an opportunity to catch the exception. Example of Rethrowing an Exception The rethrow expression can be caught by any catch whose argument matches the argument of the exception originally thrown. Related Information o Catching Exceptions o Transferring Control o Using Exception Handling o Nested try Blocks o Using a Conditional Expression in a Throw Expression o Exception Specifications ═══ Example of Rethrowing an Exception ═══ /************************************************************************ * In the following example, catch(FileIO) catches any object of type FileIO and any objects that are public base classes of the FileIO class. It then checks for those exceptions it can handle. For any exception it cannot handle, it issues a rethrow expression to rethrow the exception and allow another handler in a dynamically enclosing try block to handle the exception. * ************************************************************************/ #include class FileIO { public: int notfound; int endfile; FileIO(); // initialize data members // the following member functions throw an exception // if an input error occurs void advance(int x); void clear(); void put(int x, int y); }; // . // . // . void f() { FileIO fio; try { // call member functions of FileIO class fio.advance (1); fio.clear(); fio.put(1,-1); } catch(FileIO fexc) { if (fexc.notfound) cout << "File not Found" << endl; else if (fexc.endfile) cout << "End of File" << endl; else throw; // rethrow to outer handler } catch(...) { /* ... */ } // catch other exceptions } main() { try { f(); } catch(FileIO) { cout << "Outer Handler" << endl; } } /************************************************************************ * The rethrow expression can be caught by any catch whose argument matches the argument of the exception originally thrown. Note that, in this example, the catch(...) will not catch the rethrow expression because, when the rethrow expression is issued, control passes out of the scope of the function f() into the next dynamically enclosing block. * ************************************************************************/ ═══ 16.4.4. Using a Conditional Expression in a Throw Expression ═══ You can use a conditional expression as a throw expression. Consider the following example: #include void main() { int doit = 1; int dont = 0; float f = 8.9; int i = 7; int j = 6; try { throw doit ? i : f; } catch (int x) { cout << "Caught int " << x << endl; } catch (float x) { cout << "Caught float " << x << endl; } catch (double x) { cout << "Caught double " << x << endl; } catch (...) { cout << "Caught something " << endl; } } This example produces the following output: Caught float 7 At first glance, it looks as if the block that catches integer values should do the catch, but i is converted to a float value in the try block because it is in a conditional expression with the float value f. If the try block in the example is replaced with the following try block: try { throw doit ? i : j; } The following output is produced: Caught int 7 Related Information o Catching Exceptions o Transferring Control o Using Exception Handling o Nested try Blocks o Rethrowing an Exception o Exception Specifications ═══ 16.5. Constructors and Destructors in Exception Handling ═══ When an exception is thrown and control passes to a catch block following a try block, destructors are called for all objects constructed since the beginning of the try block directly associated with that catch block. If an exception is thrown during construction of an object consisting of subobjects or array elements, destructors will only be called for those subobjects or array elements successfully constructed before the exception was thrown. For more information on constructors and destructors, see Constructors and Destructors Overview. If a destructor detects an exception and issues a throw, the exception can be caught if the caller of the destructor was contained within a try block and an appropriate catch is coded. If an exception is thrown by a function called from an inner try block, but caught by an outer try block (because the inner try block did not have an appropriate handler), all objects constructed within both the outer and all inner try blocks are destroyed. If the thrown object has a destructor, the destructor is not called until the exception is caught and handled. Because a throw expression throws an object and a catch statement can catch an object, the object thrown enables error-related information to be transferred from the point at which an exception is detected to the exception's handler. If you throw an object with a constructor, you can construct an object that contains information relevant to the catch expression. The catch block can then access information provided by the thrown object. Example of Using Constructors in Exception Handling Exception handling can be used in conjunction with constructors and destructors to provide resource management that ensures that all locked resources are unlocked when an exception is thrown. Example of Managing Resources with Constructors and Destructors Related Information o Constructors and Destructors Overview o C++ Exception Handling Overview o Using Exception Handling o Transferring Control o Exception Specifications ═══ Managing Resources with Constructors and Destructors ═══ /************************************************************************ * Exception handling can be used in conjunction with constructors and destructors to provide resource management that ensures that all locked resources are unlocked when an exception is thrown. Consider the following example: * ************************************************************************/ class data { public: void lock(); // prevent other users from // changing the object void unlock(); // allow other users to change // the object }; void q(data&), bar(data&); // ... main() { data important; important.lock(); q(important); bar(important); important.unlock(); } /************************************************************************ * If q() or bar() throw an exception, important.unlock() will not be called and the data will stay locked. This problem can be corrected by using a helper class to write an "exception aware" program for resource management. * ************************************************************************/ class data { public: void lock(); // prevent other users from // changing the object void unlock(); // allow other users to change // the object }; class locked_data // helper class { data& real_data; public: locked_data(data& d) : real_data(d) {real_data.lock();} ~locked_data() {real_data.unlock();} }; void q(data&), bar(data&); // ... main() { data important; locked_data my_lock(important); q(important); bar(important); } /************************************************************************ * In this case, if q() or bar() throws an exception, the destructor for my_lock will be called, and the data will be unlocked. * ************************************************************************/ ═══ Example of Using Constructors in Exception Handling ═══ /************************************************************************ * In the following example, an object of class DivideByZero is thrown by the function divide(). The constructor copies the string "Division by zero" into the char array errname. Because DivideByZero is a derived class of class Matherr, the catch block for Matherr catches the thrown exception. The catch block can then access information provided by the thrown object, in this case the text of an error message. * ************************************************************************/ #include // needed for strcpy #include class Matherr { public: char errname[30]; }; class DivideByZero : public Matherr { public: DivideByZero() {strcpy (errname, "Division by zero");} }; double divide(double a, double b) { if (b == 0) throw DivideByZero(); return a/b; } void main() { double a=7,b=0; try {divide (a,b);} catch (Matherr xx) { cout << xx.errname << endl; } } ═══ 16.6. Exception Specifications ═══ C++ provides a mechanism to ensure that a given function is limited to throwing only a specified list of exceptions. An exception specification at the beginning of any function acts as a guarantee to the function's caller that the function will not throw any exception not contained in the exception specification. For example, a function: void translate() throw(unknown_word,bad_grammar) { /* ... */ } explicitly states that it will not throw any exception other than unknown_word or bad_grammar. The function translate() must handle any exceptions thrown by functions it might call, unless those exceptions are specified in the exception specification of translate(). If an exception is thrown by a function called by translate() and the exception is not handled by translate() or contained in the exception specification of translate(), unexpected() is called. Syntax of an Exception Specification If an exception is thrown from a function that has not specified the thrown exception in its exception specification, the result is a call to the function unexpected(), which is discussed in unexpected() and terminate() Functions. A function with an empty throw() specification guarantees that the function will not throw any exceptions. A function without an exception specification allows any object to be thrown from the function. The compiler does not prevent an exception specification from defining a more limited set of valid exceptions than the set of exceptions the function may actually throw. Such an error will be detected only at run time, and only if the unspecified exception is thrown. Example of Throwing an Unspecified Exception If a function with an exception specification calls a subfunction with a less restrictive exception specification (one that contains more objects than the calling function's exception specification), any thrown objects from within the subfunction that are not handled by the subfunction, and that are not part of the outer function's specification list, must be handled within the outer function. If the outer function fails to handle an exception not in its exception specification, a call to unexpected() is made. Related Information o unexpected() and terminate() Functions o C++ Exception Handling Overview o Using Exception Handling o Transferring Control ═══ Syntax of an Exception Specification ═══ The syntax of the exception specification is: ┌─,──────┐  │ >>──throw──(───┬──────┬┴──)──>< └─type─┘ The syntax of a function definition that includes an exception specification is: ┌─,──────────┐ ┌─,──────┐  │  │ >>──return-type──function-name──(───┬──────────┬┴──)──throw───┬──────┬┴──)──> └─argument─┘ └─type─┘ >──{──function-body──}──>< ═══ Example of Throwing an Unspecified Exception ═══ In the following example, NameTooShort is thrown from within a function that explicitly states that it will only throw NameTooLong. This is a valid function, although at run time, if NameTooShort is thrown, a call to unexpected() will be made. #include // needed for strlen class NameTooLong {}; class NameTooShort {}; void check(char* fname) throw (NameTooLong) { if ( strlen(fname)<4 ) throw NameTooShort(); } ═══ 16.7. unexpected() and terminate() Functions ═══ Not all thrown errors can be caught and successfully dealt with by a catch block. In some situations, the best way to handle an exception is to terminate the program. Two special library functions are implemented in C++ to process exceptions not properly handled by catch blocks or exceptions thrown outside of a valid try block. These functions are unexpected() and terminate(). When a function with an exception specification throws an exception that is not listed in its exception specification, the function unexpected() is called. Next, unexpected() calls a function specified by the set_unexpected() function. By default, unexpected() calls the function terminate(). In some cases, the exception handling mechanism will fail and a call to terminate() will be made. This terminate() call occurs in any of the following situations: o When terminate() is explicitly called o When no catch can be matched to a thrown object o When the stack becomes corrupted during the exception-handling process o When a system defined unexpected() is called The terminate() function calls a function specified by the set_terminate() function. By default, terminate calls abort(), which exits from the program. Related Information o set_unexpected() and set_terminate() o C++ Exception Handling Overview o Exception Specifications o Using Exception Handling o Transferring Control o abort - Stop a Program ═══ 16.7.1. set_unexpected() and set_terminate() ═══ The function unexpected(), when invoked, calls the function most recently supplied as an argument to set_unexpected(). If set_unexpected() has not yet been called, unexpected() calls terminate(). The function terminate(), when invoked, calls the function most recently supplied as an argument to set_terminate(). If set_terminate() has not yet been called, terminate() calls abort(), which ends the program. You can use set_unexpected() and set_terminate() to replace terminate() and abort(), respectively, with your own functions. set_unexpected() and set_terminate() are included in the standard header files . and . Each of these functions has as its return type and its argument type a pointer to function with a void return type and no arguments. The pointer to function you supply as the argument becomes the function called by the corresponding special function: the argument to set_unexpected() becomes the function called by unexpected(), and the argument to set_terminate() becomes the function called by terminate(). Both set_unexpected() and set_terminate() return a pointer to the function that was previously called by their respective special functions (unexpected() and terminate()). By saving the return values, you can restore the original special functions later so that unexpected() and terminate() will once again call terminate() and abort(). If you use set_terminate() to define your own function to replace abort(), the final action of that program should be to exit from the program. If you attempt to return from the function called by terminate(), abort() is called instead and the program ends. Note: Providing a call to longjmp() inside a user-defined terminate function can transfer execution control to some other desired point. Example of Using the Exception Handling Functions Related Information o unexpected() and terminate() Functions o C++ Exception Handling Overview o Using Exception Handling o Transferring Control o abort - Stop a Program o longjmp - Restore Stack Environment ═══ 16.7.2. Example of Using the Exception Handling Functions ═══ /************************************************************************ * The following example shows the flow of control and special functions used in exception handling: * ************************************************************************/ #include #include #include class X { /* ... */ }; class Y { /* ... */ }; class A { /* ... */ }; // pfv type is pointer to function returning void typedef void (*pfv)(); void my_terminate() { cout << "Call to my terminate" << endl; } void my_unexpected() { cout << "Call to my unexpected" << endl; } void f() throw(X,Y) // f() is permitted to throw objects of class // types X and Y only { A aobj; throw(aobj); // error, f() throws a class A object } main() { pfv old_term = set_terminate(my_terminate); pfv old_unex = set_unexpected(my_unexpected); try{ f(); } catch(X) { /* ... */ } catch(Y) { /* ... */ } catch (...) { /* ... */ } set_unexpected(old_unex); try { f();} catch(X) { /* ... */ } catch(Y) { /* ... */ } catch (...) { /* ... */ } } /************************************************************************ * At run time, this program behaves as follows: 1. The call to set_terminate() assigns to old_term the address of the function last passed to set_terminate() when set_terminate() was previously called. 2. The call to set_unexpected() assigns to old_unex the address of the function last passed to set_unexpected() when set_unexpected() was previously called. 3. Within a try block, function f() is called. Because f() throws an unexpected exception, a call to unexpected() is made. unexpected() in turn calls my_unexpected(), which prints a message to standard output and returns. 4. The second call to set_unexpected() replaces the user-defined function my_unexpected() with the saved pointer to the original function (terminate()) called by unexpected(). 5. Within a second try block, function f() is called once more. Because f() throws an unexpected exception, a call to unexpected() is again made. unexpected() automatically calls terminate(), which calls the function my_terminate(). 6. my_terminate() displays a message. It returns, and the system calls abort(), which terminates the program. At run time, the following information is displayed, and the program ends: Call to my_unexpected Call to my_terminate Note: The catch blocks following the try block are not entered, because the exception was handled by my_unexpected() as an unexpected throw, not as a valid exception. * ************************************************************************/ ═══ 17. C and C++ Compatibility ═══ The differences between ANSI C and C++ fall into two categories: o Constructs found in C++ but not in ANSI C o Constructs found in both C++ and ANSI C, but treated differently in the two languages C++ contains many constructs that are not found in ANSI C: o Single line comments beginning with // o Scope operator (::) o Free store management using the operators new and delete o Linkage specification for functions o Reference types o Default arguments for functions o Inline functions o Classes o Anonymous unions o Overloaded operators and functions o Class templates and function templates o Exception handling Note: The C/C++ Tools compiler also supports anonymous unions in C, but the implementation is slightly different from C++. For more information, see Anonymous Unions in C. ═══ 17.1. Constructs Treated Differently in C and C++ ═══ Because C++ is based on ANSI C, the two languages have many constructs in common. The use of some of these shared constructs differs, as shown here. o Character Array Initialization o Character Constants o Class and typedef Names o Class and Scope Declarations o const Object Initialization o Definitions o Definitions within Return or Argument Types o Enumerator Type o Enumeration Type o Function Declarations o Functions with an Empty Argument List o Global Constant Linkage o Jump Statements o Keywords o main() Recursion o Names of Nested Classes o Pointers to void o Prototype Declarations o Return without Declared Value o __STDC__ Macro o typedefs in Class Declarations Related Information o C and C++ Compatibility ═══ 17.1.1. Character Array Initialization ═══ In C++, when you initialize character arrays, a trailing '\0' (zero of type char) is appended to the string initializer. You cannot initialize a character array with more initializers than there are array elements. In ANSI C, space for the trailing '\0' can be omitted in this type of initialization. The following initialization, for instance, is not valid in C++: char v[3] = "asd"; // not valid in C++, valid in ANSI C because four elements are required. This initialization produces an error because there is no space for the implied trailing '\0' (zero of type char). For more information, see Arrays. ═══ 17.1.2. Character Constants ═══ A character constant has type char in C++ and int in ANSI C. See Character Constants for more information. ═══ 17.1.3. Class and typedef Names ═══ In C++, a class and a typedef cannot both use the same name to refer to a different type within the same scope (unless the typedef is a synonym for the class name). In C, a typedef name and a struct tag name declared in the same scope can have the same name because they have different name spaces. For example: void main () { typedef double db; struct db; // error in C++, valid in ANSI C typedef struct st st; // valid ANSI C and C++ } For more information on typedef, see typedef. For information on class types, see C++ Classes. For information on structures, see Structures. ═══ 17.1.4. Class and Scope Declarations ═══ In C++, a class declaration introduces the class name into the scope where it is declared and hides any object, function, or other declaration of that name in an enclosing scope. In ANSI C, an inner scope declaration of a struct name does not hide an object or function of that name in an outer scope. For example: double db; void main () { struct db // hides double object db in C++ { char* str; }; int x = sizeof(db); // size of struct in C++ // size of double in ANSI C } For more information, see Scope of Class Names. For general information about scope, see Scope in C++. ═══ 17.1.5. const Object Initialization ═══ In C++, const objects must be initialized. In ANSI C, they can be left uninitialized. For more information, see volatile and const Qualifiers. ═══ 17.1.6. Definitions ═══ An object declaration, for example: int i; is a definition in C++. In ANSI C, it is a tentative definition. In C++, a global data object must be defined only once. In ANSI C, a global data object can be declared several times without using the extern keyword. In C++, multiple definitions for a single variable cause an error. A C compilation unit can contain many identical tentative definitions for a variable. For more information, see Declarations and Definitions. ═══ 17.1.7. Definitions within Return or Argument Types ═══ In C++, types may not be defined in return or argument types. ANSI C allows such definitions. For example, the declarations: void print(struct X { int i;} x); // error in C++ enum count{one, two, three} counter(); // error in C++ produce errors in C++, but are valid declarations in ANSI C. For more information, see Function Declarations and Calling Functions and Passing Arguments. ═══ 17.1.8. Enumerator Type ═══ An enumerator has the same type as its enumeration in C++. In ANSI C, an enumeration has type int. For more information on enumerators, see Enumerations. ═══ 17.1.9. Enumeration Type ═══ The assignment to an object of enumeration type with a value that is not of that enumeration type produces an error in C++. In ANSI C, an object of enumeration type can be assigned values of any integral type. For more information, see Enumerations. ═══ 17.1.10. Function Declarations ═══ In C++, all declarations of a function must match the unique definition of a function. ANSI C has no such restriction. For more information, see Function Declarations. ═══ 17.1.11. Functions with an Empty Argument List ═══ Consider the following function declaration: int f(); In C++, this function declaration means that the function takes no arguments. In ANSI C, it could take any number of arguments, of any type. For more information, see Function Declarations. ═══ 17.1.12. Global Constant Linkage ═══ In C++, an object declared const has internal linkage, unless it has previously been given external linkage. In ANSI C, it has external linkage. For more information, see Program Linkage. ═══ 17.1.13. Jump Statements ═══ C++ does not allow you to jump over declarations containing initializations. ANSI C does allow you to use jump statements for this purpose. For more information, see Initializers. ═══ 17.1.14. Keywords ═══ C++ contains some additional keywords not found in ANSI C. ANSI C programs that use these keywords as identifiers are not valid C++ programs: catch protected class public delete template friend this inline throw new try operator virtual private For more information, see Keywords. ═══ 17.1.15. main() Recursion ═══ In C++, main() cannot be called recursively and cannot have its address taken. ANSI C allows recursive calls and allows pointers to hold the address of main(). For more information, see main. ═══ 17.1.16. Names of Nested Classes ═══ In C++, the name of a nested class is local to its enclosing class. In ANSI C, the name of the nested structure belongs to the same scope as the name of the outermost enclosing structure. For more information, see Nested Classes. ═══ 17.1.17. Pointers to void ═══ C++ allows void pointers to be assigned only to other void pointers. In ANSI C, a pointer to void can be assigned to a pointer of any other type without an explicit cast. For more information, see void Type and Pointers. ═══ 17.1.18. Prototype Declarations ═══ C++ requires full prototype declarations. ANSI C allows nonprototyped functions. For more information, see Function Declarator. ═══ 17.1.19. Return without Declared Value ═══ In C++, a return (either explicit or implicit) from main() that is declared to return a value results in a warning if no value is returned. A return (either explicit or implicit) from all other functions that is declared to return a value must return a value. In ANSI C, a function that is declared to return a value can return with no value. For more information, see Return Values. ═══ 17.1.20. __STDC__ Macro ═══ The predefined macro variable __STDC__ has the integer value 0 to indicate that C++ does not conform to ANSI C. In ANSI C, __STDC__ has the integer value 1. For more information on macros, see Predefined Macros. ═══ 17.1.21. typedefs in Class Declarations ═══ In C++, a typedef name may not be redefined in a class declaration after being used in the declaration. ANSI C allows such a declaration. For example: void main () { typedef double db; struct st { db x; double db; // error in C++, valid in ANSI C }; } For more information, see typedef. ═══ 18. Using Compiler Options ═══ You can use compiler options to alter the compilation and linking of your program. This section describes the options and tells you how to use them. The compiler options are divided into groups by function. The following list tells you which options are in each group. o Output File Management Options /F o #include File Search Options /I /X o Listing File Options /L o Debugging and Diagnostic Information Options /K /N /W /Ti /Tm /Tx o Source Code Options /S /Tc /Td /Tp o Preprocessor Options /D /P /U o Code Generation Options /G /M /Nd /Nt /O /R o Other Options /B /C /H /J /Q /Tl /V Each group of options is described in a table in this section. In the tables, the Default column states the action the compiler takes if no option is specified; the Changing Default column shows how you can change the default. Where necessary, an option is described in greater detail in a separate panel that you can link to. Related Information o Specifying Compiler Options o Using Parameters with Compiler Options o Scope of Compiler Options o Related and Conflicting Options o Language-Dependent Options o Compiler Options for Presentation Manager Programming ═══ 18.1. Specifying Compiler Options ═══ Compiler options are not case sensitive, so you can specify them in lower-, upper-, or mixed case. You can also substitute a dash (-) for the slash (/) preceding the option. For example, -Rn is equivalent to /Rn. Lower- and uppercase, dashes, and slashes can all be used on one command line, as in: icc /ls -RN -gD /Li prog.c You can specify compiler options in the following ways: o On the command line o In the ICC environment variable o In the WorkFrame/2 environment Options specified on the command line override the options in the ICC variable. Related Information o Using Parameters with Compiler Options o Scope of Compiler Options o Related and Conflicting Options o Language-Dependent Options o Compiler Options for Presentation Manager Programming o Output File Management Options o #include File Search Options o Listing File Options o Debugging and Diagnostic Information Options o Source Code Options o Preprocessor Options o Code Generation Options o Other Options ═══ Specifying Options on the Command Line ═══ Compiler options specified on the command line override any previously specified in the ICC environment variable (as described in Specifying Options in ICC). For example, to compile a source file with the multithread option, enter: icc /Gm myprog.c When compiling programs with multiple source files, an option is in effect for all the source files that follow it. The executable module will have the same file name as the first source file but with the extension .EXE. ═══ Specifying Options in ICC ═══ Frequently used command-line options can be stored in the ICC environment variable. This method is useful if you find yourself repeating the same command-line options every time you compile. You can also specify source file names in ICC. The ICC environment variable can be set either from the command line, in a command (.CMD) file, or in the CONFIG.SYS file. If it is set on the command line or by running a command file, the options will only be in effect for the current session. If it is set in the CONFIG.SYS file, the options will be in effect every time you use icc unless you override them using a .CMD file or by specifying options on the command line. For example, to specify that a source listing be generated for all compilations and that the macro DEBUG be defined to be 1, use the following command at the OS/2 prompt (or in your CONFIG.SYS file if you want these options every time you use the compiler): SET ICC=/Ls+ /DDEBUG::1 (The double colon must be used because the "=" sign is not allowed in OS/2 environment variables.) Now, type icc prog1.C to compile prog1.C. The macro DEBUG will be defined as 1, and a source listing will be produced. Options specified on the command line override the options in the ICC variable. For example, the following compiler invocation voids the effect of the ICC setting in the last example: icc /Ls- /UDEBUG fred.c ═══ Setting Options in the WorkFrame/2 Environment ═══ If you have installed the WorkFrame/2 product, you can set compiler options using the options dialogs. You can use the dialogs when you create or modify a project. Options you select while creating or changing a project are saved with that project. For more information on setting options and using the WorkFrame/2, refer to its documentation. ═══ 18.1.1. Using Parameters with Compiler Options ═══ For all compiler options that take parameters, the following rules apply: o If a parameter is required, zero or more spaces may appear between the option and the parameter. For example, both /FeMyexe.exe and /Fe Myexe.exe are valid. o If a parameter is optional, no space is allowed between the option and parameter. For example, /FlMylist.lst is valid, but /Fl Mylist.lst is not. The syntax of the compiler options varies according to the type of parameter that is used with the option. There are four types of parameters: o Strings o File names o Switches o Numbers. Related Information o Specifying Compiler Options o Scope of Compiler Options o Related and Conflicting Options o Language-Dependent Options o Compiler Options for Presentation Manager Programming o Output File Management Options o #include File Search Options o Listing File Options o Debugging and Diagnostic Information Options o Source Code Options o Preprocessor Options o Code Generation Options o Other Options ═══ Option Parameters: Strings ═══ If the option has a string parameter, the string must be enclosed by a pair of double quotation marks if there are spaces in the string. For example, /V"Version 1.0" is correct. If there are no spaces in the string, the quotation marks are not necessary. For example, both /VNew and /V"New" are valid. If the string contains double quotation marks, precede them with the backslash (\) character. For example, if the string is abc"def, specify it on the command line as "abc\"def". This combination is the only escape sequence allowed within string options. Do not end a string with a backslash, as in "abc\". Do not put a space between the option and the string. ═══ Option Parameters: File Names ═══ If you want to use a file that is in the current directory, specify only the file name. If the file you want to use is not in the current directory, specify the path and file name. For example, if your current directory is E:\, your source file is E:\myprog.c, and you compile using the defaults, your executable file will be called myprog.exe. If you want to put your executable file into the F:\ directory and call it newprog.exe, use the following command: icc /FeF:\newprog.exe myprog.c If you do not specify an extension for the executable file, .EXE is assumed. If your file name contains spaces (as permitted by the High Performance File System (HPFS)) or any elements of the HPFS extended character set, the file name must be enclosed in double quotation marks. In such a case, do not put a space between the option and a file name or directory. ═══ Option Parameters: Switches ═══ Some options are used with plus (+) or minus (-) signs. If you do not use either sign, the compiler processes the option as if you had used the + sign. When you use an option that uses switches, you can combine them. For example, the following two option specifications have the same result: /La+ /Le+ /Ls+ /Lx- /Laesx- Note that the - sign applies only to the switch immediately preceding it. ═══ Option Parameters: Numbers ═══ When an option uses a number as a parameter, do not put a space between the option and the number. When an option uses two numbers as parameters, separate the numbers with a comma. Do not leave a space between the numbers and the comma. For example: /Sg10,132 ═══ 18.2. Scope of Compiler Options ═══ The compiler options are categorized according to how they are processed. The categories are: Global A global option applies to all the source files on the command line. If a global option is specified more than once, the last occurrence of the option is the one in effect. In the following example, all the files are compiled with the /Fm- option because it follows the /Fmmap option: icc /Fmmap module1.c module2.c /Fm- module3.c A global option can follow the last file on the command line. The following options are global: /B /C /Fe /Fm /Gu /H /Mp /Ms /Ol /Q /Sd /Sn Local A local option applies only to the source files that follow the option. The last, or rightmost, occurrence of these options is the one that is in effect for the source file or files that follow it. In the following example, the file module1.c is compiled with the option /Fa- because this option follows /Fa+: icc /Fa+ /Fa- module1.c In the next example, the file module1.c is compiled with the /Fa+ option, while module2.c is compiled with /Fa-: icc /Fa+ module1.c /Fa- module2.c Note: The /D (define a preprocessor macro) is different from the other local variables in that the first definition of a macro is the one that is used. All compiler options not listed under Global are local options. Cumulative The local option /I and the global option /B have a special characteristic. Each time you specify one of them, the parameters you specify are appended to the parameters previously stated. For example, the command icc /Ia: /Ib:\cde /Ic:\fgh prog.c causes the following search path to be built: a:;b:\cde;c:\fgh Related Information o Specifying Compiler Options o Related and Conflicting Options o Language-Dependent Options o Compiler Options for Presentation Manager Programming o Output File Management Options o #include File Search Options o Listing File Options o Debugging and Diagnostic Information Options o Source Code Options o Preprocessor Options o Code Generation Options o Other Options ═══ 18.2.1. Related and Conflicting Options ═══ Related Options Some options are required with other options: o If you specify the listing file option /Le (expand macros), or one of /Li or /Lj (expand #include files), you must also specify the /Ls option to include the source code. o If you specify the /Gr option to generate code to run at ring zero, you must also specify the /Rn (no runtime environment) option. To use EXTRA, you must specify both the /Gh and /Ti options. Conflicting Options Some options are incompatible with other options. If options specified on the command line are in conflict, the following rules apply: o The syntax check option (/Fc) takes precedence over the output file generation (/Fa, /Fb, /Fe, /Fm, /Fo, and /Ft), intermediate code linker (/Fw and /Ol), and preprocessor (/P, /Pc, /Pd, and /Pe) options. o The preprocessor options (/P, /Pc, /Pd, and /Pe) take precedence over the output file generation (/Fa, /Fb, /Fe, /Fl, /Fm, /Fo, and /Ft), intermediate code linker (/Fw, /Gu, and /Ol) precompiled header file (/Fi and /Si), and all listing file (/L) options. o The option for no runtime environment (/Rn) takes precedence over the multithreading (/Gm), ddnames (/Sh), and memory file (/Sv) options. o The option to not create an object file (/Fo-) takes precedence over the option to include debug information in the object (/Ti). o The compile-only option (/C) takes precedence over the name executable module (/Fe) and generate linker map (/Fm) options. o The no-optimization option (/O-) takes precedence over the instruction scheduler option (/Os+). o The options to expand #include files in the listing (/Li and /Lj) take precedence over the precompiled header file options (/Fi and /Si). o The option to expand user and system #include files (/Lj+) takes precedence over the option to expand user #include files only (/Li). Related Information o Specifying Compiler Options o Language-Dependent Options o Compiler Options for Presentation Manager Programming o Output File Management Options o #include File Search Options o Listing File Options o Debugging and Diagnostic Information Options o Source Code Options o Preprocessor Options o Code Generation Options o Other Options ═══ 18.2.2. Language-Dependent Options ═══ Some C/C++ Tools options are only valid when compiling C programs, while others only apply to C++ programs. The following options are valid for C programs only: /Fd- Store internal work files in shared memory. C++ files must be compiled with /Fd+. /Gv Control handling of DS and ES registers for virtual device driver development. VDD support is provided for C only. /Kn Control diagnostic messages. The /Wgrp options replace the /Kn options and provide greater control over the messages. The /Kn options are mapped to the /Wgrp options for you in C programs, but are not supported for C++ programs. The /Wgrp options are supported for both C and C++. /Sg Set margins for input files. This option is provided primarily for compatibility with IBM C/370. C++ does not require any such compatibility. /Sq Set sequence numbers for input files. This option is provided primarily for compatibility with IBM C/370. C++ does not require any such compatibility. /Sr Set type conversion rules. The C++ language only supports the new type conversion rules defined by the ANSI standard. /Ss Allow use of double slashes for comments. C++ allows double slashes to indicate comments as part of the language. /S2 Allow only SAA Level 2 C constructs. There is no SAA definition of the C++ language. The following options are valid for C++ programs only: /Fb Control generation of browser files. /Ft Control generation of files for template resolution. The C language does not support templates. /Gx Control inclusion of C++ exception handling information. The C language does not include specific constructs for exception handling. /Sc Allows constructs compatible with earlier versions of the C++ language. These constructs are not allowed in C. Related Information o Specifying Compiler Options o Related and Conflicting Options o Compiler Options for Presentation Manager Programming o Output File Management Options o #include File Search Options o Listing File Options o Debugging and Diagnostic Information Options o Source Code Options o Preprocessor Options o Code Generation Options o Other Options ═══ 18.2.3. Compiler Options for Presentation Manager Programming ═══ If you are using the C/C++ Tools product to develop PM applications, you may need the following options: Option Description /Se Allow all C/C++ Tools language extensions. (This is the default.) /Gm Use the multithread libraries. /Gs- Do not remove stack probes. (This is the default.) /Wpro Produce diagnostic messages about unprototyped functions. Related Information o Specifying Compiler Options o Source Code Options o Code Generation Options o Debugging and Diagnostic Information Options o Related and Conflicting Options o Language-Dependent Options ═══ 18.3. Output File Management Options ═══ Use the options listed in this section to control the files that the compiler produces. Note: You do not need the plus symbol (+) when specifying an option: the forms /Fa+ and /Fa are equivalent. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Output File Management Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING THE │ │ │ │ │ DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fa[+|-]" │ Produce and name │ "/Fa-" │ "/Fa[+]" │ │ │ an assembler │ Do not create an │ Create an assem- │ │ "/Faname" │ listing file that │ assembler listing │ bler listing file │ │ │ has the source │ file. │ that has the same │ │ │ code as comments. │ │ name as the source │ │ │ │ │ file, with the │ │ │ NOTE: This │ │ extension ".asm". │ │ │ listing is not │ │ │ │ │ guaranteed to │ │ "/Fa"name │ │ │ compile. │ │ Create the listing │ │ │ │ │ file name".asm". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fb[+|-]" │ Produce a browser │ "/Fb-" │ "/Fb[+]" │ │ │ file. │ Do not create a │ Create a browser │ │ │ │ browser file. │ file. The file │ │ │ NOTE: This │ │ has the same name │ │ │ option is valid │ │ as the source file │ │ │ for C++ files │ │ with the extension │ │ │ only. │ │ ".brs". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fc[+|-]" │ Perform syntax │ "/Fc-" │ "/Fc[+]" │ │ │ check only. │ Compile and produce │ Do only a syntax │ │ │ │ output files │ check. The only │ │ │ │ according to other │ output files you │ │ │ │ options. │ can produce when │ │ │ │ │ this option is in │ │ │ │ │ effect are listing │ │ │ │ │ (".lst") files. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fd[+|-]" │ Specify work file │ "/Fd-" │ "/Fd[+]" │ │ │ storage area. │ Store internal work │ Store internal │ │ │ │ files in shared │ work files on disk │ │ │ │ memory. │ in the directory │ │ │ │ │ specified by the │ │ │ │ NOTE: When you │ TMP variable. │ │ │ │ compile C++ code, │ │ │ │ │ "/Fd+" becomes the │ │ │ │ │ default. You │ │ │ │ │ cannot specify │ │ │ │ │ "/Fd-" for C++ │ │ │ │ │ code. │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fename" │ Specify name of │ Give the executable │ "/Fename" │ │ │ executable file or │ file the same name │ Name the execut- │ │ │ DLL. │ as the first source │ able file │ │ │ │ file, with the │ "name.exe" or │ │ │ │ extension ".exe" or │ "name.dll". │ │ │ │ ".dll". │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fi[+|-]" │ Control creation │ "/Fi-" │ "/Fi[+]" │ │ │ of precompiled │ Do not create a │ Create a precom- │ │ │ header files. │ precompiled header │ piled header file │ │ │ │ file. │ if none exists or │ │ │ │ │ if the existing │ │ │ │ │ one is out-of- │ │ │ │ │ date. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fl[+|-]" │ Produce and name a │ "/Fl-" │ "/Fl[+]" │ │ │ listing file. │ Do not create a │ Give the listing │ │ "/Flname" │ │ listing file. │ the same file name │ │ │ │ │ as the source │ │ │ │ │ file, with the │ │ │ │ │ extension ".lst". │ │ │ │ │ │ │ │ │ │ "/Flname" │ │ │ │ │ Name the listing │ │ │ │ │ file "name.lst". │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Output File Management Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING THE │ │ │ │ │ DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fm[+|-]" │ Produce and name a │ "/Fm-" │ "/Fm[+]" │ │ │ linker map file. │ Do not create a map │ Create a linker │ │ "/Fmname" │ │ file. │ map file with the │ │ │ │ │ same file name as │ │ │ │ │ the source file, │ │ │ │ │ with the extension │ │ │ │ │ ".map". │ │ │ │ │ │ │ │ │ │ "/Fm"name │ │ │ │ │ Create map file │ │ │ │ │ "name.map". │ │ │ │ │ │ │ │ │ │ NOTE: Use the │ │ │ │ │ "/B"/map"" option │ │ │ │ │ to get a more │ │ │ │ │ detailed map file. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fo[+|-]" │ Produce and name │ "/Fo[+]" │ "/Fo-" │ │ │ an object file. │ Create an object │ Do not create an │ │ "/Fo"name │ │ file, and give it │ object file. │ │ │ │ the same name as │ │ │ │ │ the source file, │ "/Foname" │ │ │ │ with the extension │ Create object file │ │ │ │ ".obj". │ name".obj". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Ft[+|-]" │ Control generation │ "/Ft+" │ "/Ft[-]" │ │ │ of files for tem- │ Generate files for │ Do not generate │ │ "/Ftdir" │ plate resolution. │ template resolution │ files for template │ │ │ │ in the TEMPINC sub- │ resolution. │ │ │ NOTE: This │ directory under the │ │ │ │ option is valid │ current directory. │ "/Ftdir" │ │ │ for C++ files │ │ Generate the files │ │ │ only. The C lan- │ │ and place them in │ │ │ guage does not │ │ the directory dir. │ │ │ support the use of │ │ │ │ │ templates. │ │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Fw[+|-]" │ Control generation │ "/Fw-" │ "/Fw[+]" │ │ │ and use of inter- │ Perform regular │ Create interme- │ │ "/Fwname" │ mediate code │ compilation; do not │ diate code files │ │ │ files. │ save intermediate │ only; do not com- │ │ │ │ code files. │ plete compilation. │ │ │ │ │ │ │ │ │ │ "/Fwname" │ │ │ │ │ Create interme- │ │ │ │ │ diate code files │ │ │ │ │ only and name them │ │ │ │ │ "name.w, name.wh", │ │ │ │ │ and "name.wi"; do │ │ │ │ │ not complete com- │ │ │ │ │ pilation. │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ File Names and Extensions If you do not specify an extension for the file management options that take a file name as a parameter, the default extension is used. For example, if you specify /Flcome, the listing file will be called come.lst. Although you can specify an extension of your own choosing, you should use the default extensions. If you use an option without using an optional name parameter, the name of the following source file and the default extension is used, with the exception of the /Fm option. If you do not specify a name with /Fm, the name of the first file given on the command line is used, with the default extension .map. Note: If you use the /Fe option, you must specify a name or a path for the file. If you specify only a path, the file will have the same name as the first source file on the command line, with the path specified. Examples of File Management Options Related Information o Specifying Compiler Options o Listing File Options ═══ Example of File Management Options ═══ o Perform syntax check only: icc /Fc+ myprog.c o Name the object file: icc /Fobarney.obj fred.c This names the object file barney.obj instead of the default, fred.obj. o Name the executable file: icc /Febarney.exe fred.c This names the object file barney.exe instead of the default, fred.exe. o Name the listing file: icc /Floutput.my /L fred.c This creates a listing output called output.my instead of fred.lst. o Name the linker map file: icc /Fmoutput.map fred.c This creates a linker map file called output.map instead of fred.map. o Name the assembler listing file: icc /Fabarney fred.c This names the output barney.asm. instead of fred.asm. ═══ 18.4. #include File Search Options ═══ Use these options to control which paths are searched when the compiler looks for #include files. The paths that are searched are the result of the information in the INCLUDE and ICC environment variables, combined with how you use the following compiler options. ┌──────────────────────────────────────────────────────────────────────────────┐ │ #include File Search Options │ ├────────────────┬────────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Ipath[;path]"│ Specify #include │ Search directory │ "/Ipath[;path]" │ │ │ search path(s). │ of source file │ Search │ │ │ │ (for user files │ "path[;path]". │ │ │ │ only), and then │ Note that for │ │ │ │ search paths given │ user include │ │ │ │ in the INCLUDE │ files, the direc- │ │ │ │ environment vari- │ tory of the │ │ │ │ able. │ source file is │ │ │ │ │ always searched │ │ │ │ │ first. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Xc[+|-]" │ Specify whether to │ "/Xc-" │ "/Xc[+]" │ │ │ search paths spec- │ Search paths spec- │ Do not search │ │ │ ified using "/I". │ ified using "/I". │ paths specified │ │ │ │ │ using "/I". │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Xi[+|-]" │ Control INCLUDE │ "/Xi-" │ "/Xi[+]" │ │ │ environment vari- │ Search the paths │ Do not search the │ │ │ able search paths. │ specified in the │ paths specified │ │ │ │ INCLUDE environ- │ by the INCLUDE │ │ │ │ ment variable. │ environment vari- │ │ │ │ │ able. │ └────────────────┴────────────────────┴────────────────────┴───────────────────┘ The /I option must be followed by one or more directory names. A space may be included between /I and the directory name. If you specify more than one directory, separate the directory names with a semicolon. If you use the /I option more than once, the directories you specify are appended to the directories you previously specified. If you specify search paths using /I in both the ICC environment variable and on the command line, all the paths are searched. The paths specified in ICC are searched before those specified on the command line. Note: Once you use the /Xc option, the paths previously specified by using /I cannot be recovered. You have to use the /I option again if you want to reuse the paths canceled by /Xc. The /Xi option has no effect on the /Xc and /I options. Related Information o #include o Include Files o Specifying Compiler Options ═══ 18.5. Listing File Options ═══ The options listed below control whether or not a listing file is produced, the type of information in the listing, and the appearance of the file. Note: The following options only modify the appearance of a listing; they do not cause a listing to be produced. Use them with one of the other listing file options, or the /Fl option, to produce a listing: /Le /Li /Lj /Lp /Lt /Lu If you specify any of the /Le, /Li, or /Lj options, you must also specify the /L, /Lf, or /Ls option. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Listing Output Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/L[+|-]" │ Produce a listing │ "/L-" │ "/L[+]" │ │ │ file. │ Do not produce a │ Produce a listing │ │ │ │ listing file. │ file with only a │ │ │ │ │ prolog and error │ │ │ │ │ messages. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/La[+|-]" │ Include a layout │ "/La-" │ "/La[+]" │ │ │ of all referenced │ Do not include a │ Include a layout. │ │ │ "struct" and │ layout. │ │ │ │ "union" variables, │ │ │ │ │ with offsets and │ │ │ │ │ lengths. │ │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lb[+|-]" │ Include a layout │ "/Lb-" │ "/Lb[+]" │ │ │ of all "struct" │ Do not include a │ Include a layout. │ │ │ and "union" vari- │ layout. │ │ │ │ ables. │ │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Le[+|-]" │ Expand all macros. │ "/Le-" │ "/Le[+]" │ │ │ │ Do not expand │ Expand macros. │ │ │ │ macros. │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lf[+|-]" │ Set all listing │ "/Lf-" │ "/Lf[+]" │ │ │ options on or off. │ Set all listing │ Set all listing │ │ │ │ options off. │ options on. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Li[+|-]" │ Expand user │ "/Li-" │ "/Li[+]" │ │ │ #include files. │ Do not expand user │ Expand user │ │ │ │ #include files. │ #include files. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lj[+|-]" │ Expand user and │ "/Lj-" │ "/Lj[+]" │ │ │ system #include │ Do not expand user │ Expand user and │ │ │ files. │ and system #include │ system #include │ │ │ │ files. │ files. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lpnum" │ Set page length. │ "/Lp66" │ "/Lpnum" │ │ │ │ Set page length to │ Specify num lines │ │ │ │ 66 lines. │ per page of │ │ │ │ │ listing. num must │ │ │ │ │ be between 15 and │ │ │ │ │ 65535 inclusive. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Ls[+|-]" │ Include the source │ "/Ls-" │ "/Ls[+]" │ │ │ code. │ Do not include the │ Include the source │ │ │ │ source code. │ code. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lt"string""│ Set title string. │ Set title string to │ "/Lt"string"" │ │ │ │ the name of the │ Set title string │ │ │ │ source file. │ to string. │ │ │ │ │ Maximum string │ │ │ │ │ length is 256 │ │ │ │ │ characters. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lu"string""│ Set subtitle │ "/Lu""" │ "/Lu"string"" │ │ │ string. │ Set no subtitle │ Set subtitle │ │ │ │ (null string). │ string to string. │ │ │ │ │ Maximum string │ │ │ │ │ length is 256 │ │ │ │ │ characters. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Lx[+|-]" │ Generate a cross- │ "/Lx-" │ "/Lx[+]" │ │ │ reference table │ Do not generate a │ Generate a cross- │ │ │ for referenced │ cross-reference │ reference table. │ │ │ variable, struc- │ table. │ │ │ │ ture, and function │ │ │ │ │ names, that shows │ │ │ │ │ line numbers where │ │ │ │ │ names are │ │ │ │ │ declared. │ │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Ly[+|-]" │ Generate a cross- │ "/Ly-" │ "/Ly[+]" │ │ │ reference table of │ Do not generate a │ Generate a cross- │ │ │ all variable, │ cross-reference │ reference table. │ │ │ structure, and │ table. │ │ │ │ function names, │ │ │ │ │ plus all local │ │ │ │ │ variables refer- │ │ │ │ │ enced by the user. │ │ │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ Note: You can also specify titles using the #pragma title and subtitle directives, but these titles do not appear on the first page of the listing output. Related Information o #pragma title o #pragma subtitle o Output File Management Options o Specifying Compiler Options ═══ 18.6. Debugging and Diagnostic Information Options ═══ The options listed here are useful for debugging your programs. The /Wgrp options and /Kn options generate the same messages. The /Wgrp options give you greater control over the types of messages generated. The /Kn options are provided for compatibility with C Set/2 V1.0 only, and are mapped for you to the correct /Wgrp options. They are not supported for use in C++ programs, and will not be supported in future versions of the C/C++ Tools product. Note: The information generated by the C/C++ Tools debugger and the /Kn and /Wgrp options is provided to help you diagnose problems in your code. Do not use the diagnostic information as a programming interface. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Debugging Options │ ├─────────────────┬───────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Ka[+|-]" │ Control messages │ "/Ka-" │ "/Ka[+]" │ │ │ about variable │ Suppress messages │ Produce messages │ │ │ assignments that │ about assignments │ about inappro- │ │ │ can result in a │ that may cause a │ priate assign- │ │ │ loss of preci- │ loss of precision. │ ments of "long" │ │ │ sion. │ │ values. │ │ │ Maps to the │ │ │ │ │ "/Wtrd" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kb[+|-]" │ Control messages │ "/Kb-" │ "/Kb[+]" │ │ │ about basic diag- │ Suppress basic │ Produce basic │ │ │ nostics generated │ diagnostic mes- │ diagnostic mes- │ │ │ by "/K" options. │ sages. │ sages. │ │ │ Maps to the │ │ │ │ │ "/Wgen" option. │ │ │ │ │ │ │ │ │ │ NOTE: Many of │ │ │ │ │ the messages con- │ │ │ │ │ sidered general │ │ │ │ │ diagnostics in │ │ │ │ │ the C Set/2 V1.0 │ │ │ │ │ product are now │ │ │ │ │ controlled by a │ │ │ │ │ specific /W │ │ │ │ │ option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kc[+|-]" │ Control pre- │ "/Kc-" │ "/Kc[+]" │ │ │ processor warning │ Suppress pre- │ Produce pre- │ │ │ messages. │ processor warning │ processor warning │ │ │ Maps to the │ messages. │ messages. │ │ │ "/Wppc" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Ke[+|-]" │ Control messages │ "/Ke-" │ "/Ke[+]" │ │ │ about "enum" │ Suppress messages │ Produce messages │ │ │ usage. │ about "enum" │ about "enum" │ │ │ Maps to the │ usage. │ usage. │ │ │ "/Wenu" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kf[+|-]" │ Set all diag- │ "/Kf-" │ "/Kf[+]" │ │ │ nostic messages │ Set all diagnostic │ Set all diag- │ │ │ options on or │ messages options │ nostic messages │ │ │ off. │ off. │ options on. │ │ │ Maps to the │ │ │ │ │ "/Wall" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kg[+|-]" │ Control messages │ "/Kg-" │ "/Kg[+]" │ │ │ about the appear- │ Suppress messages │ Produce messages │ │ │ ance and usage of │ about "goto" │ about "goto" │ │ │ "goto" state- │ statements. │ statements. │ │ │ ments. │ │ │ │ │ Maps to the │ │ │ │ │ "/Wgot" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Ki[+|-]" │ Control messages │ "/Ki-" │ "/Ki[+]" │ │ │ about variables │ Suppress messages │ Produce messages │ │ │ that are not │ about uninitial- │ about uninitial- │ │ │ explicitly ini- │ ized variables. │ ized variables. │ │ │ tialized. │ │ │ │ │ Maps to the │ │ │ │ │ "/Wini" and │ │ │ │ │ "/Wuni" options. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Ko[+|-]" │ Control diag- │ "/Ko-" │ "/Ko[+]" │ │ │ nostic messages │ Suppress porta- │ Produce porta- │ │ │ about porta- │ bility messages. │ bility messages. │ │ │ bility. │ │ │ │ │ Maps to the │ │ │ │ │ "/Wpor" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kp[+|-]" │ Control messages │ "/Kp-" │ "/Kp[+]" │ │ │ about function │ Suppress messages │ Produce messages │ │ │ parameters that │ about unused func- │ about unused │ │ │ are not used. │ tion parameters. │ function parame- │ │ │ Maps to the │ │ ters. │ │ │ "/Wpar" option. │ │ │ └─────────────────┴───────────────────┴────────────────────┴───────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Debugging Options │ ├─────────────────┬───────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kr[+|-]" │ Control messages │ "/Kr-" │ "/Kr[+]" │ │ │ about mapping of │ Suppress messages │ Produce messages │ │ │ names to the │ about name │ about name │ │ │ linkage editor. │ mapping. │ mapping. │ │ │ Maps to the │ │ │ │ │ "/Wtru" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kt[+|-]" │ Control pre- │ "/Kt-" │ "/Kt[+]" │ │ │ processor trace │ Suppress pre- │ Produce pre- │ │ │ messages. │ processor trace │ processor trace │ │ │ Maps to the │ messages. │ messages. │ │ │ "/Wppt" option. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Kx[+|-]" │ Control messages │ "/Kx-" │ "/Kx[+]" │ │ │ about variables │ Suppress messages │ Produce messages │ │ │ and functions │ about unreferenced │ about unrefer- │ │ │ that have │ external variables │ enced external │ │ │ external declara- │ and functions. │ variables and │ │ │ tions, but are │ │ functions. │ │ │ never used. │ │ │ │ │ Maps to the │ │ │ │ │ "/Wext" and │ │ │ │ │ "/Wuse" options. │ │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Nn" │ Set maximum │ Set no limit on │ "/Nn" │ │ │ number of errors │ number of errors. │ End compilation │ │ │ before compila- │ │ when error count │ │ │ tion aborts. │ │ reaches n. │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Ti[+|-]" │ Generate │ "/Ti-" │ "/Ti[+]" │ │ │ C/C++ Tools │ Do not generate │ Generate debugger │ │ │ debugger informa- │ debugger informa- │ information. │ │ │ tion. │ tion. │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Tm[+|-]" │ Enable debug ver- │ "/Tm-" │ "/Tm+" │ │ │ sions of memory │ Use the regular │ Use the debug │ │ │ management func- │ versions of the │ memory management │ │ │ tions. │ memory management │ functions │ │ │ │ functions │ (_debug_calloc, │ │ │ │ ("calloc", │ _debug_malloc, │ │ │ │ "malloc", "new", │ "new", and so │ │ │ │ and so on). │ on). This option │ │ │ │ │ also defines the │ │ │ │ │ "__DEBUG_ALLOC__" │ │ │ │ │ macro. See the C │ │ │ │ │ Library Reference │ │ │ │ │ for information │ │ │ │ │ on the C debug │ │ │ │ │ memory management │ │ │ │ │ functions and the │ │ │ │ │ Online Language │ │ │ │ │ Reference for │ │ │ │ │ information on │ │ │ │ │ the debug ver- │ │ │ │ │ sions of "new" │ │ │ │ │ and "delete". │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/Tx[+|-]" │ Control informa- │ "/Tx-" │ "/Tx[+|-]" │ │ │ tion generated │ Provide only the │ Provide a com- │ │ │ when an exception │ exception message │ plete machine- │ │ │ occurs. │ and address when │ state dump when │ │ │ │ an exception │ an exception │ │ │ │ occurs; do not │ occurs. │ │ │ │ provide a complete │ │ │ │ │ machine-state │ │ │ │ │ dump. │ │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/W[+|-]" │ Control diag- │ "/Wall-" │ "/Wgrp" │ │ │ nostic messages. │ Do not generate │ Generate messages │ │ │ │ diagnostic mes- │ in the grp group. │ │ │ │ sages. │ More than one │ │ │ │ │ group may be │ │ │ │ │ specified. See │ │ │ │ │ the section which │ │ │ │ │ follows for │ │ │ │ │ descriptions of │ │ │ │ │ the different │ │ │ │ │ groups of mes- │ │ │ │ │ sages. │ └─────────────────┴───────────────────┴────────────────────┴───────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Debugging Options │ ├─────────────────┬───────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────────┼───────────────────┼────────────────────┼───────────────────┤ │ "/W[0|1|2|3]" │ Set the severity │ "/W3" │ "/W0" │ │ │ level of message │ Produce and count │ Produce and count │ │ │ the compiler │ all message types │ only severe │ │ │ produces and that │ (severe error, │ errors. │ │ │ causes the error │ error, warning, │ │ │ │ count to incre- │ and informa- │ "/W1" │ │ │ ment. See the │ tional). │ Produce and count │ │ │ Online Language │ │ severe errors and │ │ │ Reference for a │ │ errors. │ │ │ description of │ │ │ │ │ error messages │ │ "/W2" │ │ │ and severity │ │ Produce and count │ │ │ levels. │ │ severe errors, │ │ │ │ │ errors, and │ │ │ │ │ warnings. │ └─────────────────┴───────────────────┴────────────────────┴───────────────────┘ Note: If you use the /Ti option to generate debugger information, it is recommended that you turn optimization off (/O-). (This recommendation does not apply if you are using /Ti to generate information for EXTRA.) Using the /Wgrp Options Related Information o Specifying Compiler Options o Compiler Messages and Return Codes ═══ 18.6.1. Using the /Wgrp Diagnostic Options ═══ The /Wgrp options control informational messages that warn of possible programming errors, weak programming style, and other information about the structure of your programs. Similar messages are in groups, or suboptions, to give you greater control over which types of messages you want to generate. When you specify /Wall[+], all suboptions are turned on and all possible diagnostic messages are reported. Because even a simple program that contains no errors can produce many informational messages, you may not want to use /Wall very often. You can use the suboptions alone or in combination to specify the type of messages that you want the compiler to report. Suboptions can be separated by an optional + sign. To turn off a suboption, you must place a - sign after it. You can also combine the /W[0|1|2|3] options with the /Wgrp options. The following table lists the message groups and the message numbers that each controls, as well as the /Kn option that formerly controlled each message. Messages generated for C files begin with EDC0, while messages for C++ files begin with EDC3. ┌──────────────────────────────────────────────────────────────────────────────┐ │ /Wgrp Options │ ├─────────┬─────────┬─────────────────────────────┬────────────────────────────┤ │ GRP │ /K │ CONTROLS MESSAGES ABOUT │ MESSAGES │ │ │ OPTION │ │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "all" │ "/Kf" │ All diagnostics. │ All message numbers listed │ │ │ │ │ in this table. │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cls" │ (none) │ Use of classes │ EDC3110, EDC3253, EDC3266 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cmp" │ (none) │ Possible redundancies in │ EDC3138, EDC3139, EDC3140 │ │ │ │ unsigned comparisons. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cnd" │ "/Kb" │ Possible redundancies or │ EDC0816, EDC0821, EDC0822, │ │ │ │ problems in conditional │ EDC3107, EDC3130 │ │ │ │ expressions. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cns" │ "/Kb" │ Operations involving con- │ EDC0823, EDC0824, EDC0838, │ │ │ │ stants. │ EDC0839, EDC0865, EDC0866, │ │ │ │ │ EDC0867, EDC3131, EDC3219 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cnv" │ "/Kb" │ Conversions. │ EDC3313 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "cpy" │ (none) │ Problems generating copy │ EDC3199, EDC3200 │ │ │ │ constructors. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "eff" │ "/Kb" │ Statements with no effect. │ EDC0811, EDC0812, EDC0813, │ │ │ │ │ EDC0814, EDC0815, EDC3165, │ │ │ │ │ EDC3215 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "enu" │ "/Ke" │ Consistency of "enum" vari- │ EDC0830, EDC0831, EDC3137 │ │ │ │ ables. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ext" │ "/Kb" │ Unused external defi- │ EDC0803, EDC0804, EDC0810, │ │ │ and │ nitions. │ EDC3127 │ │ │ "/Kx" │ │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "gen" │ "/Kb" │ General diagnostics. │ EDC0807, EDC0809, EDC0826, │ │ │ │ │ EDC0835, EDC0868, EDC0869, │ │ │ │ │ EDC3101 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "gnr" │ (none) │ Generation of temporary │ EDC3151 │ │ │ │ variables. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "got" │ "/Kg" │ Usage of "goto" statements. │ EDC0832, EDC0837 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ini" │ "/Ki" │ Possible problems with │ EDC0861, EDC0862, EDC0863, │ │ │ │ initialization. │ EDC0864 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "lan" │ (none) │ Effects of the language │ EDC3116 │ │ │ │ level. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "obs" │ "/Kb" │ Features that are obsolete. │ EDC0827, EDC0828 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ord" │ "/Kb" │ Unspecified order of evalu- │ EDC0829 │ │ │ │ ation. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "par" │ "/Kp" │ Unused parameters. │ EDC0800, EDC3126 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "por" │ "/Ko, │ Nonportable language con- │ EDC0464, EDC0819, EDC0820, │ │ │ /Kb" │ structs. │ EDC3132, EDC3133, EDC3135, │ │ │ │ │ EDC3136 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ppc" │ "/Kc" │ Possible problems with │ EDC0836, EDC0841, EDC0842, │ │ │ │ using the preprocessor. │ EDC0843, EDC0844, EDC0845, │ │ │ │ │ EDC0846, EDC0847, EDC0848 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ppt" │ "/Kt" │ Trace of preprocessor │ EDC0851, EDC0852, EDC0853, │ │ │ │ actions. │ EDC0854, EDC0855, EDC0856, │ │ │ │ │ EDC0857, EDC0858, EDC0859, │ │ │ │ │ EDC0860, EDC0870 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "pro" │ "/Kb" │ Missing function proto- │ EDC0185 │ │ │ │ types. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "rea" │ "/Kb" │ Code that cannot be │ EDC0825, EDC3119 │ │ │ │ reached. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "ret" │ "/Kb" │ Consistency of "return" │ EDC0833, EDC0834, EDC3128 │ │ │ │ statements. │ │ └─────────┴─────────┴─────────────────────────────┴────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ /Wgrp Options │ ├─────────┬─────────┬─────────────────────────────┬────────────────────────────┤ │ GRP │ /K │ CONTROLS MESSAGES ABOUT │ MESSAGES │ │ │ OPTION │ │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "trd" │ "/Ka" │ Possible truncation or loss │ EDC0817, EDC0818, EDC3108, │ │ │ │ of data or precision. │ EDC3135, EDC3136 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "tru" │ "/Kr" │ Variable names truncated by │ EDC0244 │ │ │ │ the compiler. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "und" │ (none) │ Casting of pointers to or │ EDC3098 │ │ │ │ from an undefined class. │ │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "uni" │ "/Ki" │ Uninitialized variables. │ EDC0808 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "use" │ "/Kb, │ Unused "auto" and "static" │ EDC0801, EDC0802, EDC0805, │ │ │ /Kx" │ variables. │ EDC0806, EDC3002, EDC3099, │ │ │ │ │ EDC3100 │ ├─────────┼─────────┼─────────────────────────────┼────────────────────────────┤ │ "vft" │ (none) │ Generation of virtual func- │ EDC3280, EDC3281, EDC3282 │ │ │ │ tion tables. │ │ └─────────┴─────────┴─────────────────────────────┴────────────────────────────┘ More information about the messages generated by the /Wgrp options is available in Compiler Messages and Return Codes. Examples of /Wgrp Options Related Information o Specifying Compiler Options o Compiler Messages and Return Codes ═══ Examples of /Wgrp Options ═══ o Produce all diagnostic messages: icc /Wall blue.c icc /Wall+ blue.c o Produce diagnostic messages about: - Unreferenced parameters - Missing function prototypes - Uninitialized variables by turning on the appropriate suboptions: icc /Wpar+pro+uni blue.c icc /Wparprouni blue.c o Produce all diagnostic messages except: - Warnings about assignments that can cause a loss of precision - Preprocessor trace messages - External variable warnings by turning on all options, and then turning off the ones you do not want: icc /Wall+trd-ppt-ext- blue.c o Produce only basic diagnostics, with all other suboptions turned off: icc /Wgen+ blue.c o Produce only basic diagnostics and messages about severe errors, errors, or warnings (/W2): icc /Wgen2 blue.c ═══ 18.7. Source Code Options ═══ These options control how the C/C++ Tools compiler interprets your source file. This control is especially useful, for example, if you are migrating code or ensuring consistency with a particular language standard. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Source Code Options │ ├────────────────┬────────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/S[a|c|e|2]" │ Set language │ "/Se" │ "/Sa" │ │ │ level. │ Allow all │ Conform to ANSI │ │ │ │ C/C++ Tools lan- │ standards. │ │ │ │ guage extensions. │ │ │ │ │ │ "/Sc" │ │ │ │ │ Allow constructs │ │ │ │ │ compatible with │ │ │ │ │ older levels of │ │ │ │ │ the C++ language. │ │ │ │ │ │ │ │ │ │ NOTE: This │ │ │ │ │ option is valid │ │ │ │ │ only for C++ │ │ │ │ │ files. │ │ │ │ │ │ │ │ │ │ "/S2" │ │ │ │ │ Conform to SAA │ │ │ │ │ Level 2 stand- │ │ │ │ │ ards. │ │ │ │ │ │ │ │ │ │ NOTE: This │ │ │ │ │ option is valid │ │ │ │ │ only for C files. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sd[+|-]" │ Set default file │ "/Sd-" │ "/Sd[+]" │ │ │ extension. │ Set the default │ Set the default │ │ │ │ file extension as │ file extension as │ │ │ │ ".obj". │ ".c". │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sg[l][,]│ Set left and right │ "/Sg-" │ "/Sg[l][,r|*]" │ │ │ margins of the │ Do not set any │ Set left margin │ │ "/Sg-" │ input file and │ margins: use the │ to "l". The │ │ │ ignore text │ entire input file. │ right margin can │ │ │ outside these │ │ be the value r, │ │ │ margins. Useful │ │ or an asterisk │ │ │ when using source │ │ can be used to │ │ │ files that contain │ │ denote no right │ │ │ characters that │ │ margin. "l" and │ │ │ you want to │ │ r must be between │ │ │ ignore. │ │ 1 and 65535 │ │ │ │ │ inclusive, and r │ │ │ NOTE: This │ │ must be greater │ │ │ option is only │ │ than or equal to │ │ │ valid for C files. │ │ "l". │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sh[+|-]" │ Control use of │ "/Sh-" │ "/Sh[+]" │ │ │ ddnames. │ Do not allow │ Allow use of │ │ │ │ ddnames. │ ddnames. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Si[+|-]" │ Control use of │ "/Si-" │ "/Si[+]" │ │ │ precompiled header │ Do not use precom- │ Use precompiled │ │ │ files. │ piled header │ header files if │ │ │ │ files. │ they exist and │ │ │ │ │ are current. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sm[+|-]" │ Control compiler │ "/Sm-" │ "/Sm[+]" │ │ │ interpretation of │ Treat unsupported │ Ignore unsup- │ │ │ unsupported 16-bit │ 16-bit keywords │ ported 16-bit │ │ │ keywords, such as │ like any other │ keywords. │ │ │ "near" and "far". │ identifier. │ │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sn[+|-]" │ Control use of │ "/Sn-" │ "/Sn[+]" │ │ │ double-byte char- │ Do not allow use │ Allow use of │ │ │ acter set (DBCS). │ of DBCS. │ DBCS. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sp[1|2|4]" │ Specify alignment │ "/Sp4" │ "/Sp[1|2]" │ │ │ or packing of data │ Align structures │ Align structures │ │ │ items within │ and unions along │ and unions along │ │ │ structures and │ 4-byte boundaries │ 1-byte or 2-byte │ │ │ unions. │ (normal align- │ boundaries. │ │ │ │ ment). │ "/Sp" is equiv- │ │ │ │ │ alent to "/Sp1". │ └────────────────┴────────────────────┴────────────────────┴───────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Source Code Options │ ├────────────────┬────────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sq[l][,]│ Specify columns in │ "/Sq-" │ "/Sq[l][,r|*]" │ │ │ which sequence │ Use no sequence │ Sequence numbers │ │ "/Sq-" │ numbers appear, │ numbers. │ appear between │ │ │ and ignore text in │ │ columns "l" and r │ │ │ those columns. │ │ of each line in │ │ │ This option can be │ │ the input source │ │ │ used when │ │ code. "l" and r │ │ │ importing source │ │ must be between 1 │ │ │ files from other │ │ and 65535 inclu- │ │ │ systems. │ │ sive, and r must │ │ │ │ │ be greater than │ │ │ NOTE: This │ │ or equal to "l". │ │ │ option is only │ │ If you do not │ │ │ valid for C files. │ │ want to specify a │ │ │ │ │ right column, use │ │ │ │ │ an asterisk for │ │ │ │ │ r. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sr[+|-]" │ Set type conver- │ "/Sr-" │ "/Sr[+]" │ │ │ sion rules. │ Use new-style │ Use old-style │ │ │ │ rules for type │ rules for type │ │ │ NOTE: This │ conversion. New- │ conversion. Old- │ │ │ option is valid │ style rules pre- │ style rules pre- │ │ │ for C files only. │ serve accuracy. │ serve the sign. │ │ │ │ │ They do not │ │ │ │ │ conform to ANSI │ │ │ │ │ standards. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Ss[+|-]" │ Allow use of │ "/Ss-" │ "/Ss[+]" │ │ │ double slashes │ Do not allow │ Allow the double │ │ │ ("//") for com- │ double slashes to │ slash format to │ │ │ ments. │ indicate comments. │ indicate com- │ │ │ │ │ ments. This type │ │ │ NOTE: This │ │ of comment is │ │ │ option is only │ │ ended by a car- │ │ │ valid for C files. │ │ riage return. │ │ │ C++ allows double │ │ │ │ │ slashes to indi- │ │ │ │ │ cate comments as │ │ │ │ │ part of the lan- │ │ │ │ │ guage. │ │ │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Su[+|-|1|2|4]│ Control size of │ "/Su-" │ "/Su[+]" │ │ │ "enum" variables. │ Use the SAA rules: │ Make all "enum" │ │ │ │ make all "enum" │ variables 4 │ │ │ │ variables the size │ bytes. │ │ │ │ of the smallest │ │ │ │ │ integral type that │ "/Su1" │ │ │ │ can contain all │ Make all "enum" │ │ │ │ variables. │ variables 1 byte. │ │ │ │ │ │ │ │ │ │ "/Su2" │ │ │ │ │ Make all "enum" │ │ │ │ │ variables 2 │ │ │ │ │ bytes. │ │ │ │ │ │ │ │ │ │ "/Su4" │ │ │ │ │ Make all "enum" │ │ │ │ │ variables 4 │ │ │ │ │ bytes. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Sv[+|-]" │ Allow use of │ "/Sv-" │ "/Sv[+]" │ │ │ memory files. │ Do not allow │ Allow use of │ │ │ │ memory files. │ memory files. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Tc" │ Specify that the │ Compile ".cpp" and │ "/Tc" │ │ │ following file is │ ".cxx" files as │ Compile the fol- │ │ │ a C file. │ C++ files, and │ lowing file as a │ │ │ │ ".c" and all other │ C source file, │ │ │ IMPORTANT: The │ unrecognized files │ regardless of its │ │ │ "/Tc" option MUST │ as C files. │ extension. │ │ │ be immediately │ │ │ │ │ followed by a file │ │ │ │ │ name, and applies │ │ │ │ │ only to that file. │ │ │ └────────────────┴────────────────────┴────────────────────┴───────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Source Code Options │ ├────────────────┬────────────────────┬────────────────────┬───────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Td[c|p]" │ Specify default │ "/Td" │ "/Tdc" │ │ │ language (C or │ Compile ".cpp" and │ Compile all │ │ │ C++) for files. │ ".cxx" files as │ source and unrec- │ │ │ │ C++ files, and │ ognized files │ │ │ │ ".c" and all other │ that follow on │ │ │ │ unrecognized files │ the command line │ │ │ │ as C files. │ as C files. │ │ │ │ │ │ │ │ │ │ "/Tdp" │ │ │ │ │ Compile all │ │ │ │ │ source and unrec- │ │ │ │ │ ognized files │ │ │ │ │ that follow on │ │ │ │ │ the command line │ │ │ │ │ as C++ files, and │ │ │ │ │ ensure that tem- │ │ │ │ │ plate functions │ │ │ │ │ are resolved cor- │ │ │ │ │ rectly. │ │ │ │ │ │ │ │ │ │ NOTE: You can │ │ │ │ │ specify "/Td" │ │ │ │ │ anywhere on the │ │ │ │ │ command line to │ │ │ │ │ return to the │ │ │ │ │ default rules for │ │ │ │ │ the files that │ │ │ │ │ follow it. │ ├────────────────┼────────────────────┼────────────────────┼───────────────────┤ │ "/Tp" │ Specify that the │ Compile ".cpp" and │ "/Tp" │ │ │ following file is │ ".cxx" files as │ Compile the fol- │ │ │ a C++ file. │ C++ files, and │ lowing file as a │ │ │ │ ".c" and all other │ C++ source file, │ │ │ IMPORTANT: The │ unrecognized files │ regardless of its │ │ │ "/Tp" option MUST │ as C files. │ extension. │ │ │ be immediately │ │ │ │ │ followed by a file │ │ │ │ │ name, and applies │ │ │ │ │ only to that file. │ │ │ └────────────────┴────────────────────┴────────────────────┴───────────────────┘ Additional information is available on: o Using the /Sd Option o Using the /Tdp Option for Template Resolution Related Information o #pragma langlvl o #pragma pack o _Packed Qualifier o #pragma margins o #pragma sequence o Comments o Specifying Compiler Options ═══ 18.7.1. Using the /Sd Option ═══ This option specifies whether a file without an extension should be considered a C source file or an object file, and whether it should be compiled and linked or just linked. When using the default (/Sd-), you must specify the extension when using a source file: icc anthony.c icc efrem.cpp If you omit the extension, the C/C++ Tools compiler assumes that the file is an object file (.obj) and does not compile it, but only invokes the linker. The following commands are equivalent (assuming that /Sd+ has not been specified elsewhere, such as in ICC). icc dale icc dale.obj icc /Sd- dale If you want the default file extension to be the default source file extension, use the /Sd+ option. For example, the following two commands are equivalent: icc alistair.c icc /Sd+ alistair Note: The /Tc and /Tp options override the setting of /Sd. If you specify either /Tc or /Tp followed by a file name without an extension, the compiler looks for the name specified, without an extension, and treats the file as a C file (if /Tc was specified) or a C++ file (if /Tp was specified). For example, given the following command: icc /Tp xiaohu the compiler searches for the file xiaohu and compiles it as a C++ file. ═══ 18.7.2. Using the /Tdp Option for Template Resolution ═══ When you link C++ object or intermediate code files, you must use icc to invoke the linker and you must specify the /Tdp option. For example: icc /Tdp /Ol tammy.w trish.w icc /Tdp wang.obj This ensures that any template functions you use are resolved correctly, among other things. You can use the /B option to pass options to the linker. ═══ 18.8. Preprocessor Options ═══ The options listed here control the use of the preprocessor. Note that the /Pc, /Pd, and /Pe options are actually suboptions of /P. Specifying /Pc- is the same as specifying /P+c- and causes only the preprocessor to be run. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Preprocessor Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ /Dname[::n]│ Define pre- │ Define no macros on │ /Dname[::n] │ │ or │ processor macros │ command line. │ or │ │ /Dname[=n] │ to specified │ │ /Dname[=n] │ │ │ values. │ │ │ │ │ │ │ Define pre- │ │ │ │ │ processor macro │ │ │ │ │ name to the value │ │ │ │ │ n. If n is │ │ │ │ │ omitted, the macro │ │ │ │ │ is set to a null │ │ │ │ │ string. Macros │ │ │ │ │ defined on the │ │ │ │ │ command line over- │ │ │ │ │ ride macros │ │ │ │ │ defined in the │ │ │ │ │ source code. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/P[+|-]" │ Control the pre- │ "/P-" │ "/P[+]" │ │ │ processor. │ Run the pre- │ Run the pre- │ │ │ │ processor and com- │ processor only. │ │ │ │ piler. Do not │ Create a pre- │ │ │ │ generate pre- │ processor output │ │ │ │ processor output. │ file that has the │ │ │ │ │ same name as the │ │ │ │ │ source file, with │ │ │ │ │ the extension │ │ │ │ │ ".i". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Pc[+|-]" │ Preserve source │ "/P-" │ "/Pc-" │ │ │ code comments in │ Run the pre- │ Run the pre- │ │ │ preprocessor │ processor and com- │ processor only. │ │ │ output. │ piler. Do not │ Create a pre- │ │ │ │ generate pre- │ processor output │ │ │ │ processor output. │ file and strip out │ │ │ │ │ any comments. The │ │ │ │ │ output file has │ │ │ │ │ the same name as │ │ │ │ │ the source file, │ │ │ │ │ with the extension │ │ │ │ │ ".i". │ │ │ │ │ │ │ │ │ │ "/Pc[+]" │ │ │ │ │ Run the pre- │ │ │ │ │ processor only. │ │ │ │ │ Create a pre- │ │ │ │ │ processor output │ │ │ │ │ file that includes │ │ │ │ │ the comments from │ │ │ │ │ the source code. │ │ │ │ │ The output file │ │ │ │ │ has the same name │ │ │ │ │ as the source │ │ │ │ │ file, with the │ │ │ │ │ extension ".i". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Pd[+|-]" │ Redirect pre- │ "/P-" │ "/Pd-" │ │ │ processor output. │ Run the pre- │ Run the pre- │ │ │ │ processor and com- │ processor only. │ │ │ │ piler. Do not │ Do not redirect │ │ │ │ generate pre- │ preprocessor │ │ │ │ processor output. │ output. Write │ │ │ │ │ preprocessor │ │ │ │ │ output to a file │ │ │ │ │ that has the same │ │ │ │ │ name as the source │ │ │ │ │ file, with the │ │ │ │ │ extension ".I". │ │ │ │ │ │ │ │ │ │ "/Pd[+]" │ │ │ │ │ Run the pre- │ │ │ │ │ processor only. │ │ │ │ │ Send the pre- │ │ │ │ │ processor output │ │ │ │ │ to "stdout". │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Preprocessor Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Pe[+|-]" │ Suppress "#line" │ "/P-" │ "/Pe-" │ │ │ directives in pre- │ Run the pre- │ Run the pre- │ │ │ processor output. │ processor and com- │ processor only. │ │ │ │ piler. Do not │ Generate "#line" │ │ │ │ generate pre- │ directives in the │ │ │ │ processor output. │ preprocessor │ │ │ │ │ output. The │ │ │ │ │ output file has │ │ │ │ │ the same name as │ │ │ │ │ the source file, │ │ │ │ │ with the extension │ │ │ │ │ ".i". │ │ │ │ │ │ │ │ │ │ "/Pe[+]" │ │ │ │ │ Run the pre- │ │ │ │ │ processor only. │ │ │ │ │ Suppress creation │ │ │ │ │ of "#line" direc- │ │ │ │ │ tives in pre- │ │ │ │ │ processor output. │ │ │ │ │ The output file │ │ │ │ │ has the same name │ │ │ │ │ as the source │ │ │ │ │ file, with the │ │ │ │ │ extension ".i". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/U" │ Undefine macros. │ Retain macros. │ "/Uname" │ │ │ │ │ Undefine macro │ │ │ │ │ name. │ │ │ │ │ │ │ │ │ │ "/U*" │ │ │ │ │ Undefine all │ │ │ │ │ macros. │ │ │ │ │ │ │ │ │ │ NOTE: "/U" does │ │ │ │ │ not affect the │ │ │ │ │ macros "__DATE__, │ │ │ │ │ __TIME__, │ │ │ │ │ __TIMESTAMP__, │ │ │ │ │ __FILE__", and │ │ │ │ │ "__FUNCTION", nor │ │ │ │ │ does it undefine │ │ │ │ │ macros defined in │ │ │ │ │ source code. │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ Additional information is available on Using the Preprocessor. Related Information o Preprocessor Directives o Predefined Macros o Specifying Compiler Options ═══ 18.8.1. Using the Preprocessor ═══ Preprocessor directives, such as #include, allow you to include C or C++ code from another source file into yours, to define macros, and to expand macros. See Preprocessor Directives for a list of preprocessor directives and information on how to use them. If you run only the preprocessor, you can use the preprocessor output (which has all the preprocessor directives executed, but no code compiled) to debug your program. For example, all macros are expanded, and the code for all files included by #include directives appears in your program. By default, comments in the source code are not included in the preprocessor output. To preserve the comments, use the /Pc option. For C programs, if you use // to begin your comments, you must also specify the /Ss option to include those comments in the preprocessor output. The /P, /Pc, /Pd, and /Pe options can be used in combination with each other. For example, to preserve comments, suppress #line directives, and redirect the preprocessor output to stdout, specify /Pcde. ═══ 18.9. Code Generation Options ═══ These options specify the type of code that the compiler will produce. Notes: o The /Oi[+] option is more effective when /O[+] is also specified. o Using optimization (/O[+]) limits your use of the C/C++ Tools debugger to debug your code. The /Ti option is not recommended for use with optimization. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Code Generation Options │ ├─────────────┬─────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gd[+|-]" │ Specify static or │ "/Gd-" │ "/Gd[+]" │ │ │ dynamic linking of │ Statically link the │ Dynamically link │ │ │ the runtime │ runtime library. │ to the runtime │ │ │ library. │ All external names │ library. │ │ │ │ beginning with the │ │ │ │ │ letters "Dos", │ │ │ │ │ "Kbd", and "Vio" │ │ │ │ │ are reserved. This │ │ │ │ │ restriction does │ │ │ │ │ not apply when com- │ │ │ │ │ piling with "/Gd+". │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Ge[+|-]" │ Specify creation of │ "/Ge[+]" │ "/Ge-" │ │ │ an ".EXE" or a │ Build an ".EXE" │ Build a ".DLL" │ │ │ ".DLL" file. │ file. │ file. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gf[+|-]" │ Specify fast │ "/Gf-" │ "/Gf[+]" │ │ │ floating-point exe- │ Do not use fast │ Use fast floating- │ │ │ cution. │ floating-point exe- │ point execution. │ │ │ │ cution. │ │ │ │ If your program │ │ │ │ │ does not need to │ │ │ │ │ abide by ANSI rules │ │ │ │ │ regarding the proc- │ │ │ │ │ essing of "double" │ │ │ │ │ and "float" types, │ │ │ │ │ you can use this │ │ │ │ │ option to increase │ │ │ │ │ your program's per- │ │ │ │ │ formance. Because │ │ │ │ │ the fast floating- │ │ │ │ │ point method does │ │ │ │ │ not perform all the │ │ │ │ │ conversions speci- │ │ │ │ │ fied by the ANSI │ │ │ │ │ standards, the │ │ │ │ │ results obtained │ │ │ │ │ may differ from │ │ │ │ │ results obtained │ │ │ │ │ using ANSI methods, │ │ │ │ │ but are often more │ │ │ │ │ precise. │ │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gh[+|-]" │ Generate code │ "/Gh-" │ "/Gh[+]" │ │ │ enabled for EXTRA │ Do not enable code │ Enable code to be │ │ │ and other profiling │ for EXTRA. │ run by EXTRA and │ │ │ tools. │ │ other profiling │ │ │ │ │ tools by generated │ │ │ │ │ profiler hooks in │ │ │ │ │ function prologs. │ │ │ │ │ │ │ │ │ │ NOTE: To enable │ │ │ │ │ code for EXTRA, │ │ │ │ │ you must also │ │ │ │ │ specify "/Ti". │ └─────────────┴─────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Code Generation Options │ ├─────────────┬─────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gi[+|-]" │ Specify fast │ "/Gi-" │ "/Gi[+]" │ │ │ integer execution. │ Do not use fast │ Use fast integer │ │ │ │ integer execution. │ execution. │ │ │ If you are shifting │ │ │ │ │ bits by a variable │ │ │ │ │ amount, you can use │ │ │ │ │ fast integer exe- │ │ │ │ │ cution to ensure │ │ │ │ │ that for values │ │ │ │ │ greater than 31, │ │ │ │ │ the bits are │ │ │ │ │ shifted by the │ │ │ │ │ result of a modulo │ │ │ │ │ 32 of the value. │ │ │ │ │ Otherwise, the │ │ │ │ │ result of the shift │ │ │ │ │ is 0. │ │ │ │ │ │ │ │ │ │ NOTE: If your │ │ │ │ │ shift value is a │ │ │ │ │ constant greater │ │ │ │ │ than 32, the result │ │ │ │ │ will always be 0. │ │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gm[+|-]" │ Choose single or │ "/Gm-" │ "/Gm[+]" │ │ │ multithread │ Link with the │ Link with the │ │ │ libraries. │ single-thread │ multithread │ │ │ │ version of the │ version of the │ │ │ │ library (no multi- │ library. │ │ │ │ thread capabili- │ │ │ │ │ ties). │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gn[+|-]" │ Control generation │ "/Gn-" │ "/Gn[+]" │ │ │ of default library │ Provide linker │ Do not provide │ │ │ information in │ information about │ linker information │ │ │ object. │ the default │ about default │ │ │ │ libraries according │ libraries. All │ │ │ │ to other "/G" │ libraries must be │ │ │ │ options. │ explicitly speci- │ │ │ │ │ fied at link time. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gr[+|-]" │ Generate object │ "/Gr-" │ "/Gr[+]" │ │ │ code that runs at │ Do not allow object │ Allow object code │ │ │ ring 0. Use this │ code to run at ring │ to run at ring 0. │ │ │ option if you are │ 0. │ │ │ │ writing code, such │ │ │ │ │ as device drivers │ │ │ │ │ or operating │ │ │ │ │ systems, that will │ │ │ │ │ run at ring 0 │ │ │ │ │ instead of ring 3. │ │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gs[+|-]" │ Remove stack probes │ "/Gs-" │ "/Gs[+]" │ │ │ from the generated │ Do not remove stack │ Remove stack │ │ │ code. │ probes. │ probes. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gt[+|-]" │ Enable tiled memory │ "/Gt-" │ "/Gt[+]" │ │ │ and store variables │ Do not enable vari- │ Enable all vari- │ │ │ such that they may │ ables to be passed │ ables to be passed │ │ │ be passed to 16-bit │ to 16-bit func- │ to 16-bit func- │ │ │ functions. │ tions. │ tions. Static and │ │ │ │ │ external variables │ │ │ │ │ are mapped into │ │ │ │ │ 16-bit segments. │ │ │ │ │ Variables larger │ │ │ │ │ than 64K will be │ │ │ │ │ aligned on, but │ │ │ │ │ will still cross, │ │ │ │ │ 64K boundaries. │ │ │ │ │ When this option │ │ │ │ │ is specified, the │ │ │ │ │ memory management │ │ │ │ │ functions "calloc, │ │ │ │ │ free, malloc," and │ │ │ │ │ "realloc" are │ │ │ │ │ mapped to the │ │ │ │ │ tiled versions │ │ │ │ │ "_tcalloc, _tfree, │ │ │ │ │ _tmalloc", and │ │ │ │ │ "_trealloc". │ └─────────────┴─────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Code Generation Options │ ├─────────────┬─────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gu[+|-]" │ Tell intermediate │ "/Gu-" │ "/Gu[+]" │ │ │ linker whether │ External functions │ The data is used │ │ │ external functions │ may use data │ only within the │ │ │ use data defined in │ defined in the │ intermediate files │ │ │ the intermediate │ intermediate files │ being linked, with │ │ │ link. │ being linked. │ the exception of │ │ │ │ │ data that is │ │ │ │ │ exported using │ │ │ │ │ "_Export", │ │ │ │ │ "#pragma export", │ │ │ │ │ or a ".DEF" file. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gv[+|-]" │ Control handling of │ "/Gv-" │ "/Gv[+]" │ │ │ DS and ES registers │ Do not perform any │ Save the DS and ES │ │ │ for virtual device │ special handling of │ registers on entry │ │ │ driver development. │ the DS and ES reg- │ to an external │ │ │ │ isters. │ function, set them │ │ │ NOTE: This option │ │ to the selector │ │ │ is valid for C │ │ for DGROUP, then │ │ │ files only. │ │ restore them on │ │ │ Virtual device │ │ exit from the │ │ │ driver development │ │ function. │ │ │ is not supported │ │ │ │ │ for C++ programs. │ │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gw[+|-]" │ Control generation │ "/Gw-" │ "/Gw[+]" │ │ │ of "FWAIT" instruc- │ Do not generate │ Generate "FWAIT" │ │ │ tion after each │ "FWAIT" instruction │ instruction after │ │ │ floating-point load │ after each │ each floating- │ │ │ instruction. │ floating-point load │ point load │ │ │ │ instruction. │ instruction. This │ │ │ │ │ allows the program │ │ │ │ │ to take a │ │ │ │ │ floating-point │ │ │ │ │ stack overflow │ │ │ │ │ exception imme- │ │ │ │ │ diately after the │ │ │ │ │ load instruction │ │ │ │ │ that caused it. │ │ │ │ │ │ │ │ │ │ NOTE: This │ │ │ │ │ option is not │ │ │ │ │ recommended │ │ │ │ │ because it │ │ │ │ │ increases the size │ │ │ │ │ of your executable │ │ │ │ │ file and greatly │ │ │ │ │ decreases its per- │ │ │ │ │ formance. You do │ │ │ │ │ not need this │ │ │ │ │ option unless you │ │ │ │ │ call assembler │ │ │ │ │ code that leaves a │ │ │ │ │ different number │ │ │ │ │ of values on the │ │ │ │ │ floating point │ │ │ │ │ stack. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Gx[+|-]" │ Controls removal of │ "/Gx-" │ "/Gx[+]" │ │ │ C++ exception han- │ Do not remove C++ │ Remove C++ excep- │ │ │ dling information. │ exception handling │ tion handling │ │ │ │ information. │ information. │ │ │ NOTE: This option │ │ │ │ │ is valid for C++ │ │ │ │ │ files only. │ │ │ └─────────────┴─────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Code Generation Options │ ├─────────────┬─────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/G[3|4|5]" │ Specify type of │ "/G3" │ "/G4" │ │ │ processor. │ Optimize code for │ Optimize code for │ │ │ │ use with a 386 │ use with a 486 │ │ │ │ processor. The │ processor. The │ │ │ │ code will run on a │ code will run on a │ │ │ │ 486 or Pentium │ 386 or Pentium │ │ │ │ microprocessor. │ microprocessor. │ │ │ │ The compiler │ The compiler │ │ │ │ includes any 486 or │ includes any │ │ │ │ Pentium micro- │ Pentium micro- │ │ │ │ processor optimiza- │ processor opti- │ │ │ │ tions that do not │ mizations that do │ │ │ │ detract from the │ not detract from │ │ │ │ performance on the │ the performance on │ │ │ │ 386 processor. If │ the 486 processor. │ │ │ │ you do not know │ │ │ │ │ what processor your │ "/G5" │ │ │ │ application will be │ Optimize code for │ │ │ │ run on, use this │ use with a Pentium │ │ │ │ option. │ Microprocessor. │ │ │ │ │ The code will run │ │ │ │ │ on a 386 or 486 │ │ │ │ │ processor. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/M[p|s]" │ Set calling conven- │ "/Mp" │ "/Ms" │ │ │ tion. │ Use _Optlink │ Use _System │ │ │ │ linkage for func- │ linkage for func- │ │ │ │ tions. You must │ tions. You must │ │ │ │ include the Toolkit │ include the │ │ │ │ header files to │ C/C++ Tools │ │ │ │ call OS/2 APIs. │ library header │ │ │ │ │ files to call │ │ │ │ │ C/C++ Tools func- │ │ │ │ │ tions. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Ndname" │ Specify names of │ Use the default │ "/Ndname" │ │ │ default data and │ names DATA32 and │ Use the names │ │ │ constant segments. │ CONST32. │ nameDATA32 and │ │ │ │ │ nameCONST32. You │ │ │ │ │ can then give the │ │ │ │ │ segments special │ │ │ │ │ attributes. The │ │ │ │ │ renamed segments │ │ │ │ │ are not placed in │ │ │ │ │ the default data │ │ │ │ │ group. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Ntname" │ Specify name of │ Use the default │ "/Ntname" │ │ │ default code or │ name CODE32. │ Use the name │ │ │ text segment. │ │ nameCODE32. You │ │ │ │ │ can then give the │ │ │ │ │ segment special │ │ │ │ │ attributes. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/O[+|-]" │ Control optimiza- │ "/O-" │ "/O[+]" │ │ │ tion. │ Do not optimize │ Optimize code. │ │ │ │ code. │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Oi[+|-|]" │ Control inlining of │ "/Oi-" │ "/Oi[+]" │ │ │ user code. │ Do not inline any │ Inline all user │ │ "/Oivalue" │ │ user code. │ functions quali- │ │ │ │ │ fied with the │ │ │ │ NOTE: When "/O+" │ "_Inline" or │ │ │ │ is specified, │ "inline" keyword. │ │ │ │ "/Oi+" becomes the │ │ │ │ │ default. │ "/Oivalue" │ │ │ │ │ Inline all user │ │ │ │ │ functions quali- │ │ │ │ │ fied with the │ │ │ │ │ "_Inline" or │ │ │ │ │ "inline" keyword │ │ │ │ │ or that are │ │ │ │ │ smaller than value │ │ │ │ │ in abstract code │ │ │ │ │ units. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Ol[+|-]" │ Control use of │ "/Ol-" │ "/Ol[+]" │ │ │ intermediate code │ Do not pass code │ Pass code through │ │ │ linker. │ through the inter- │ the intermediate │ │ │ │ mediate linker. │ linker before gen- │ │ │ │ │ erating an object │ │ │ │ │ file. │ └─────────────┴─────────────────────┴─────────────────────┴────────────────────┘ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Code Generation Options │ ├─────────────┬─────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Om[+|-]" │ Control size of │ "/Om-" │ "/Om[+]" │ │ │ working set for │ Do not limit │ Limit working set │ │ │ compiler. The com- │ working set size. │ size to approxi- │ │ │ piler may use a │ │ mately 35M. │ │ │ large amount of │ │ │ │ │ memory when │ │ NOTE: Because │ │ │ inlining user code, │ │ this option may │ │ │ especially when │ │ cause the compiler │ │ │ performing auto- │ │ to disregard some │ │ │ matic inlining at │ │ inlining opportu- │ │ │ large thresholds │ │ nities, code gen- │ │ │ ("/Oi50" and │ │ erated with "/Om-" │ │ │ higher). │ │ may be more effi- │ │ │ │ │ cient. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Op[+|-]" │ Control disabling │ "/Op+" │ "/Op-" │ │ │ of optimizations │ Perform optimiza- │ Do not perform │ │ │ involving the stack │ tions involving the │ optimizations that │ │ │ pointer. │ stack pointer. │ involve the stack │ │ │ │ │ pointer. Code │ │ │ │ │ that directly │ │ │ │ │ manipulates the │ │ │ │ │ stack pointer │ │ │ │ │ should be compiled │ │ │ │ │ with this option. │ │ │ │ │ This option is not │ │ │ │ │ recommended │ │ │ │ │ because it │ │ │ │ │ decreases the per- │ │ │ │ │ formance of your │ │ │ │ │ executable file. │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/Os[+|-]" │ Control use of │ "/Os-" │ "/Os+" │ │ │ instruction sched- │ Do not invoke the │ Invoke the │ │ │ uler. │ instruction sched- │ instruction sched- │ │ │ │ uler. │ uler. │ │ │ │ │ │ │ │ │ NOTE: When "/O+" │ NOTE: You cannot │ │ │ │ is specified, │ specify "/Os+" and │ │ │ │ "/Os+" becomes the │ "/O-". │ │ │ │ default. │ │ ├─────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ "/R[e|n]" │ Control executable │ "/Re" │ "/Rn" │ │ │ runtime environ- │ Generate executable │ Generate execut- │ │ │ ment. │ code that runs in a │ able code that can │ │ │ │ C/C++ Tools runtime │ be used as a sub- │ │ │ │ environment. │ system without a │ │ │ │ │ runtime environ- │ │ │ │ │ ment. │ └─────────────┴─────────────────────┴─────────────────────┴────────────────────┘ Additional information is available on Using the /Ge Option. Related Information o Linkage Keywords o #pragma linkage o Specifying Compiler Options ═══ 18.9.1. Using the /Ge Option ═══ The C/C++ Tools libraries provide two initialization routines, one for executable modules and one for DLLs. For each object file, the compiler must include a reference to the appropriate initialization routine. The name of this routine is then passed to the linker when the file is linked. Use the /Ge option at compile time to tell the compiler which routine to reference. The /Ge- option causes the compiler to generate a reference to _dllentry for every module compiled. The /Ge+ option generates a reference to _exeentry only if a main function is found in the source. If no main function is included, no linking reference is generated. If you want to create a library of objects that can be linked into either an executable file or a DLL, use the /Ge+ option when you compile. Typically, none of these objects would contain a reference to main. If one of the objects did contain a reference to main, you can override the /Ge option when you link your files. Create a source file that defines the routine already referenced in your object file. In the same file, add a dummy statement that references the correct initialization routine. Then compile this file and link it with your other object files. For example, if you compiled kim.obj using the /Ge+ option, but want to link it to create a DLL, your extra source file would contain statements like the following: int _exeentry = 1; extern int _dllentry; int main(void) { int x; . . . x = _dllentry; . . . } The reference to _exeentry in kim.obj is resolved by this file, and this file's reference to _dllentry causes the linker to link in the correct initialization routine. ═══ 18.10. Other Options ═══ Use these options to control linker parameters, logo display, default char type, and other C/C++ Tools options. ┌──────────────────────────────────────────────────────────────────────────────┐ │ Other Options │ ├──────────────┬────────────────────┬─────────────────────┬────────────────────┤ │ OPTION │ DESCRIPTION │ DEFAULT │ CHANGING DEFAULT │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/B"options""│ Specify parameters │ "/B""" │ "/B"options"" │ │ │ to be passed to │ Pass only the icc │ Pass options │ │ │ linker. │ default parameters │ string to the │ │ │ │ to the linker. See │ linker as parame- │ │ │ See the Toolkit │ "Finishing Your │ ters. The icc │ │ │ Tools Reference │ Program" in the │ default parameters │ │ │ for information │ Programming Guide │ are also passed. │ │ │ about the options │ for a description │ │ │ │ you can pass to │ of the options │ │ │ │ the LINK386 │ passed to the │ │ │ │ linker. │ linker by default. │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/C[+|-]" │ Perform compile │ "/C-" │ "/C[+]" │ │ │ only, or perform │ Perform compile and │ Perform compile │ │ │ compile and link. │ invoke linker. │ only, no link. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Hnum" │ Set significant │ "/H255" │ "/H"num │ │ │ length of external │ Set the first 255 │ Set the first num │ │ │ names. │ characters of │ characters of │ │ │ │ external names to │ external names to │ │ │ │ be significant. │ be significant. │ │ │ │ │ The value of num │ │ │ │ │ must be between 6 │ │ │ │ │ and 255 inclusive. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/J[+|-]" │ Set default "char" │ "/J[+]" │ "/J-" │ │ │ type. │ Set unspecified │ Set unspecified │ │ │ │ "char" variables to │ "char" variables │ │ │ │ "unsigned char". │ to "signed char". │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Q[+|-]" │ Display compiler │ "/Q-" │ "/Q[+]" │ │ │ logo when invoking │ Display logo on │ Do not display │ │ │ compiler. │ "stderr". │ logo. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/Tl[+|-|valu│]Control preloading │ "/Tl[+]" │ "/Tlvalue" │ │ │ of the compiler. │ Preload the com- │ Preload the com- │ │ │ │ piler components as │ piler components │ │ │ │ required. A compo- │ as required and │ │ │ │ nent remains in │ keep the files in │ │ │ │ memory for 10 │ memory for value │ │ │ │ minutes. If it is │ minutes. │ │ │ │ referenced in that │ │ │ │ │ time, the timer │ "/Tl-" │ │ │ │ starts again. Each │ Do not preload the │ │ │ │ compiler component │ compiler. You can │ │ │ │ has its own timer. │ specify this │ │ │ │ │ option without a │ │ │ │ NOTE: This option │ file name to │ │ │ │ is not available if │ unload any compo- │ │ │ │ you are using the │ nents that are │ │ │ │ OS/2 2.0 operating │ loaded. │ │ │ │ system without the │ │ │ │ │ Service Pack. │ │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "/V"string"" │ Include a version │ "/V""" │ "/V"string"" │ │ │ string in the │ Set no version │ Set version string │ │ │ object and execut- │ string. │ to string. The │ │ │ able files. │ │ length of the │ │ │ │ │ string can be up │ │ │ │ │ to 256 characters. │ ├──────────────┼────────────────────┼─────────────────────┼────────────────────┤ │ "?" │ Display list of │ (none) │ "?" │ │ │ compiler options │ │ Display list of │ │ │ with descriptions. │ │ compiler options │ │ │ │ │ with descriptions. │ └──────────────┴────────────────────┴─────────────────────┴────────────────────┘ Examples of Other Options Related Information o #pragma chars o Specifying Compiler Options ═══ Examples of Other Options ═══ o Passing a parameter to the linker: icc /B"/NOI" fred.c The /NOI option tells the linker to preserve the case of external names in fred.obj. o Imbedding a version string or copyright: icc /V"Version 1.0" fred.c This imbeds the version notice in fred.obj. ═══ 19. Compiler Messages and Return Codes ═══ These panels contain information about the compile-time messages and should not be used as programming interface information. For every compilation job or job step, the compiler generates a return code that indicates to the operating system the degree of success or failure it achieved. The meanings of the return codes are: Code Meaning 0 No error detected; compilation completed; successful execution anticipated. OR Possible error (warning) detected; compilation completed; successful execution probable. 12 Error detected; compilation may have been completed; successful execution impossible. 16 Severe error detected; compilation terminated abnormally; successful execution impossible. 20 Fatal error detected; compilation terminated abnormally and abruptly; successful execution impossible. The compiler message format is: filename.ext(line:col): ss EDCnnnn: text where: filename.ext - file name (with extension) where the error occurred line - line where the error occurred col - column where the error occurred ss - error severity: 00 - informational 10 - warning 30 - error 40 - severe error 50 - fatal error nnnn - error message number text - message text, which may contain substitution text indicated by &n The message text is prefixed with the severity string (for example, warning), not with the severity number. Message numbers in the range of 0001 to 2999 are generated for C code. Message numbers in the range of 3000 to 3999 are generated for C++ code. Message numbers in the 4000 range are generated for both C and C++ code. Messages other than those in the 4000 range are prefixed with the name of the file and the line and column number where the message was generated. For messages in the 4000 range, the file name and line number where the error occurred follow the message text. The severity of errors for these messages is determined dynamically as the error occurs. If the error is unrecognized by the compiler, it is prefaced by unknown error. If one of these messages is generated, contact your IBM Service representative. There are four messages that are generated if the message files cannot be accessed. They are: o Cannot find the message. o Cannot access the message file. o The message file format is not valid. o Cannot find the message file. If one of these messages is generated, ensure that o The DPATH variable is set in your CONFIG.SYS file o The message files are in a directory in the DPATH o The DPATH allows read access to the directories specified o The file system is functioning properly o The message files are not corrupted. Reinstall the message files if any have been corrupted. Reboot the system. If the problem persists, contact your IBM Service Representative. ═══ 19.1. EDC0001 ═══ Internal compiler error at procedure &1. An error occurred during compilation. Recovery: Contact your IBM Service Representative. ═══ 19.2. EDC0002 ═══ Unexpected compiler error #&1&2 occurred. An error occurred which the compiler was not able to recover from. Recovery: Contact your IBM Service Representative. ═══ 19.3. EDC0003 ═══ Compilation aborted by user. Ctrl-Break or Ctrl-C was pressed to stop the compiler. Recovery: None. ═══ 19.4. EDC0041 ═══ Identifier &1 must be declared before it is used. A C identifier must be declared before it is used in an expression. Recovery: Declare an identifier of that name in the current scope or in a higher scope. ═══ 19.5. EDC0042 ═══ A declaration must declare a variable, a tag, or enum members. A data type cannot be followed by a semicolon or an enum tag without the list of enum constants. Recovery: Add a variable name to the data type or provide the list of enum constants to complete the declaration. ═══ 19.6. EDC0043 ═══ A type must be specified in the declaration of the object &1. A declaration must always specify the type of the object declared or the return type of the function declared. A missing type (an object name followed by a semicolon) does not default to int. Recovery: Declare the object or function with a type. ═══ 19.7. EDC0044 ═══ An incomplete struct or union tag cannot be used in a declaration. Only pointer declarations can include incomplete types. A struct or union tag is undefined if the list describing the name and type of its members has not been specified. Recovery: Define the tag before it is used in the declaration of an identifier or complete the declaration. ═══ 19.8. EDC0045 ═══ The enum constants must be specified when the enum tag is declared. When an enumeration tag is declared, the list of the enumeration constants must be included in the declaration. Recovery: Add the list of enumeration constants in the enum tag declaration. ═══ 19.9. EDC0047 ═══ External objects cannot be initialized in a block. A variable has been declared at block scope with storage class extern, and has been given an explicit initializer. This is not permitted. Recovery: Initialize the external object in the external declaration. ═══ 19.10. EDC0049 ═══ The pragma &1 directive has already been specified for function &2. Only one of pragma inline and pragma noinline can be specified for a single function. The second pragma specified will be ignored. Recovery: Remove one of the conflicting pragmas. ═══ 19.11. EDC0050 ═══ A C reserved word cannot appear in a #pragma directive. A reserved word, such as int or break, has been used in a #pragma directive. This can cause unexpected results, so it is not permitted. Recovery: Replace the reserved word by the name of a function or variable. ═══ 19.12. EDC0060 ═══ Length of bit-field &1 must be less than or equal to 32 bits. The bit-field length must not exceed the maximum bit size of the bit-field type. Recovery: Define the bit-field length to be less than or equal to 32 bits. ═══ 19.13. EDC0061 ═══ Bit-field &1 must have type signed int or unsigned int. Recovery: Define the bit-field with a type signed int or unsigned int. ═══ 19.14. EDC0062 ═══ A bit-field with a zero length must be unnamed. A named bit-field must have a positive length; a zero length bit-field is used for alignment only, and must not be named. Recovery: Redefine the bit-field with a length greater than zero or remove the name of the bit-field. ═══ 19.15. EDC0063 ═══ Length of bit-field &1 must be a constant expression. Recovery: Replace the expression that specifies the length of the bit-field with a constant expression. ═══ 19.16. EDC0064 ═══ Length of bit-field &1 must be positive. Recovery: Replace the constant expression that specifies the length of the bit-field with a positive value. ═══ 19.17. EDC0065 ═══ Length of bit-field &1 must be a constant integral expression. Recovery: Replace the constant expression that specifies the length of the bit-field with a constant integral expression. ═══ 19.18. EDC0067 ═══ A struct or union member cannot be declared with a storage class. A storage class specifier was found in the declaration of a struct or union member. Members automatically take on the same storage class as their parent structure or union. Recovery: Remove the storage class specifier from the member of the struct or union. ═══ 19.19. EDC0068 ═══ The &1 definition must specify a member list. The declaration of a struct or a union that includes an empty member list enclosed between braces is not a valid struct or union definition. Recovery: Specify the members of the struct or union in the definition or remove the empty braces to make it a simple struct or union tag declaration. ═══ 19.20. EDC0069 ═══ A member declaration must specify a name. A struct or union member declaration must specify a name. A type cannot be followed by a semicolon. Recovery: Declare the member with a name. ═══ 19.21. EDC0080 ═══ An object cannot be cast to an struct, union or function type. An attempt was made to cast an operand to an aggregate, union or function type. Recovery: Use pointers instead of struct, union or function objects. Cast the pointer operand to a pointer to the struct, union or function type. ═══ 19.22. EDC0081 ═══ A struct or union cannot be cast to another data type. Recovery: Use a pointer to the struct or union as the operand. ═══ 19.23. EDC0082 ═══ The data conversion is not valid. The statement contains an expression that converts data to a type that is not valid. See Type Conversions for the table of correct data conversions. Recovery: Check the type declaration of the indicated operand and the type of the conversion. Ensure the conversion is correct. ═══ 19.24. EDC0083 ═══ Only casts to arithmetic types are allowed in an arithmetic constant expression. In an arithmetic constant expression, casts must be to arithmetic types. Valid arithmetic types include: char, signed and unsigned int, enum, float, double, and long double. Recovery: Remove the cast operator or change the cast to an arithmetic one. ═══ 19.25. EDC0096 ═══ The subscript must be a constant integral expression. Recovery: Replace the expression that specifies the array subscript by a constant integral expression. ═══ 19.26. EDC0097 ═══ Pointers to void and pointers to function are not assignment compatible. Recovery: Ensure that your function declarations are correct. ═══ 19.27. EDC0098 ═══ Pointers to void and pointers to function cannot be compared. Recovery: Check the logic of the comparison. ═══ 19.28. EDC0099 ═══ A pointer to an incomplete type cannot be subscripted. Recovery: Define the type before you reference it. ═══ 19.29. EDC0100 ═══ Operand of bitwise complement must have integral type. The operand of the bitwise complement operator does not have an integral type. Valid integral types include: signed and unsigned char; signed and unsigned short, long, and int; and enum. Recovery: Change the type of the operand, or use a different operand. ═══ 19.30. EDC0101 ═══ Operand of unary minus operator must have arithmetic type. The operand of the unary minus operator (-) does not have an arithmetic type. Valid arithmetic types include: signed and unsigned char; signed and unsigned short, long, and int; enum, float, double, and long double. Recovery: Change the type of the operand, or use a different operand. ═══ 19.31. EDC0102 ═══ Operand of logical negation must have scalar type. The operand of the logical negation operator (!) does not have a scalar type. Valid scalar types include: signed and unsigned char; signed and unsigned short, long, and int; enum, float, double, long double, and pointers. Recovery: Change the type of the operand, or use a different operand. ═══ 19.32. EDC0103 ═══ This size of this type is zero. The sizeof operator cannot be used on a void type. If it is, the compiler returns zero for the size of the expression. Recovery: Ensure that sizeof() is used on a valid type. ═══ 19.33. EDC0104 ═══ Only pointers to compatible types can be subtracted. The expression must contain pointers to compatible data types. See Pointer Arithmetic for the rules on compatible types. Recovery: Ensure that the pointers point to compatible data types. ═══ 19.34. EDC0105 ═══ Operand of address operator must be a function or an lvalue. The operand of the address operator (unary &) is not valid. The operand must be either a function designator or an lvalue that designates an object that is not a bit-field and is not declared with register storage class. Recovery: Change the operand. ═══ 19.35. EDC0106 ═══ The sizeof operator cannot be used with a function, void or bit-field. The operand of the sizeof operator is not valid. The sizeof operator cannot be applied to an expression that has a function type or an incomplete type, to the parenthesized name of such a type, or to an lvalue that designates a bit-field object. Recovery: Change the operand. ═══ 19.36. EDC0107 ═══ Operand of indirection operator must be a pointer. The operand of the indirection operator (unary *) is not a pointer. Recovery: Change the operand. ═══ 19.37. EDC0108 ═══ Operand of arrow operator must be a pointer to a struct or union. The left hand operand of the arrow operator (->) must have type "pointer to structure" or "pointer to union". Recovery: Change the operand. ═══ 19.38. EDC0109 ═══ The subscript must be an integral expression. The subscript expression must have integral type. Valid integral types include: char, signed and unsigned int, and enum. Recovery: Change the subscript expression to have an integral type. ═══ 19.39. EDC0110 ═══ Operand of dot operator must be a struct or a union. The left hand operand of the dot (.) operator is not of type struct or union. Recovery: Change the operand. ═══ 19.40. EDC0111 ═══ Identifier &1 must be a member of the struct or union. The specified member does not belong to the structure or union given. One of the following has occurred: o The right hand operand of the dot (.) operator is not a member of the structure or union specified on the left hand side of the operator. o The right hand operand of the arrow (->) operator is not a member of the structure or union pointed to by the pointer on the left hand side of the operator. Recovery: Change the identifier. ═══ 19.41. EDC0112 ═══ The expression must be a function designator. The expression is followed by an argument list but does not evaluate to a function designator. Recovery: Change the expression to be a function or a pointer to a function. ═══ 19.42. EDC0113 ═══ Operand must have integral type. The operand of the bitwise operators or modulus (%) operator must have integral type. Valid integral types include: char, signed and unsigned int, and enum. Recovery: Change the operand. ═══ 19.43. EDC0114 ═══ Operand must be a modifiable lvalue. See Lvalue for a description of lvalue. Recovery: Change the operand. ═══ 19.44. EDC0115 ═══ A struct or union can be assigned only to a compatible type. Two structures have compatible types if both have been declared with the same structure tag. Two unions have compatible types if both have been declared with the same union tag. However, tags are scope sensitive. Even if two tag names and their member lists are identical, if their definitions are located in different scopes, the types associated with these tags are different. Recovery: Ensure that the structures or unions used in the assignment have been declared with the same tag in the same scope. ═══ 19.45. EDC0116 ═══ Identifier &1 cannot be redeclared as an enum tag. In the declaration, the object is declared to be an enum tag. The object was previously declared to the tag of a struct or union type. Recovery: Change the name of the tag. ═══ 19.46. EDC0117 ═══ The operation between these types is not valid. The identifiers on the left hand side and the right hand side of the operator have types that do not conform to the restrictions of the operator. The operation specified in the expression cannot be performed. See Expressions and Operators for the list of operator restrictions. Recovery: Change the operands. ═══ 19.47. EDC0118 ═══ The divisor for the modulus or division operator cannot be zero. The value of the divisor expression cannot be zero. Recovery: Change the expression used as the divisor. ═══ 19.48. EDC0119 ═══ The void pointer must be cast prior to this operation. A void pointer must be cast to a data type before it is used in this operation. Recovery: Cast the pointer to a type other than void prior to this operation. ═══ 19.49. EDC0120 ═══ Operand of unary plus operator must have arithmetic type. The operand of the unary plus operator (+) does not have an arithmetic type. Valid arithmetic types include: signed and unsigned char; signed and unsigned short, long, and int; enum, float, double, and long double. Recovery: Change the operand. ═══ 19.50. EDC0121 ═══ Operand must have scalar type. The operand for this operation does not have scalar type. Valid scalar types include: signed and unsigned char; signed and unsigned short, long, and int; enum, float, double, long double, and pointers. Recovery: Change the type of the operand, or use a different operand. ═══ 19.51. EDC0122 ═══ Operand must have arithmetic type. The operand of this operation does not have arithmetic type. Valid arithmetic types include: signed and unsigned char; signed and unsigned short, long, and int; enum, float, double, and long double. Recovery: Change the operand. ═══ 19.52. EDC0123 ═══ If one operand is void, the other must be void. If one operand in the conditional expression has type void, the other operand must also have type void. Recovery: Make the operands compatible. ═══ 19.53. EDC0125 ═══ Operands of the conditional operator must have compatible types. If one operand of the conditional expression has type struct or union, the other operand must be a struct or union declared using the same tag in the same scope. Two structures have compatible types if both have been declared with the same structure tag. Two unions have compatible types if both have been declared with the same union tag. However, tags are scope sensitive. Even if two tag names and their member lists are identical, if their definitions are located in different scopes, the types associated with these tags are different. Recovery: Ensure that the structures or unions used in the conditional expression have been declared/defined with the same tag (in the same scope). ═══ 19.54. EDC0126 ═══ If one operand is a pointer, the other must also be a pointer. If one of the result operands of a conditional expression is a pointer, the other result operand must be either a pointer to the same qualified or unqualified type, a NULL pointer, or a pointer to void. Recovery: Change the operands. ═══ 19.55. EDC0127 ═══ If the operands are pointers, they must point to compatible types. If one operand of either the relational or the equality operator is a pointer, the other operand must be either a pointer to the same qualified or unqualified type, a NULL pointer, or a pointer to void. Recovery: Change the operands. ═══ 19.56. EDC0128 ═══ Two pointers cannot be added. The addition operator requires that either both operands have arithmetic type or, if one of the operands is a pointer, the other one must have integral type. Valid integral types include: char, signed and unsigned int, and enum. Valid arithmetic types include: the integral types plus float, double, long double, and bit fields. Recovery: Change the operands. ═══ 19.57. EDC0130 ═══ The operation cannot be performed on an incomplete struct or union. The definition of the operand must be completed prior to this operation. A structure or union type is completed when the definition of its tag is specified. A struct or union tag is defined when the list describing the name and type of its members is specified. Recovery: Define the tag before using it in an expression. ═══ 19.58. EDC0131 ═══ Subtraction between void pointers is not allowed. Recovery: Cast the pointers to a type other than void or do not subtract them. ═══ 19.59. EDC0132 ═══ A pointer to void cannot be subscripted. The subscript operator requires a pointer to a valid address. Recovery: Cast the pointer to a type other than void before using it with the subscript operator. ═══ 19.60. EDC0133 ═══ An identifier cannot be declared in a cast or sizeof expression. Only abstract declarators can appear in cast or sizeof expressions. Recovery: Remove the identifier from the cast or sizeof expression and replace it with an abstract declarator. ═══ 19.61. EDC0136 ═══ The sizeof operator cannot be used with arrays of unknown size. Recovery: Ensure the array and its size have been declared before using it with the sizeof operator. ═══ 19.62. EDC0137 ═══ The indirection operator cannot be applied to a pointer to an incomplete struct or union. Except for pointers, it is not valid to declare an object of incomplete structure or union type. A structure or union is incomplete when the definition of its tag has not been specified. A struct or union tag is undefined when the list describing the name and type of its members has not been specified. Recovery: Define the tag before using it in the declaration of an identifier. ═══ 19.63. EDC0138 ═══ The indirection operator cannot be applied to a void pointer. The indirection operator requires a pointer to a valid address. Recovery: Cast the pointer to a type other than void before using it with the indirection operator. ═══ 19.64. EDC0139 ═══ A translation unit must contain at least one external declaration. A translation unit that does not contain any external declaration will not be linked to. Normally it will not affect the execution of the executable program. Recovery: Ensure this is what was intended or change the appropriate declarations to the external ones. ═══ 19.65. EDC0140 ═══ Operand has type &1. An error has occurred due to conflicting operands. This message states the type of the operand used in the expression. Recovery: No recovery is necessary if this result was intended. Change the type of the operand if necessary. ═══ 19.66. EDC0141 ═══ Prototype has type &1. An error has occurred due to conflicting function declarations. This message states the type of the prototype declaration. Recovery: No recovery is necessary if this result was intended. Change the type of the prototype if necessary. ═══ 19.67. EDC0142 ═══ Previous declaration has type &1. An error has occurred due to conflicting identifier declarations. This message states the type of the identifier in the current declaration. Recovery: No recovery is necessary if this result was intended. Change the declarations to the same type if necessary. ═══ 19.68. EDC0143 ═══ The pre- and post- increment and decrement operators cannot be applied to void pointers. Pointers to void cannot be incremented or decremented. Recovery: Cast the pointer to a type other than void before using it with any of the increment or decrement operators. ═══ 19.69. EDC0145 ═══ Redeclaration has type &1. An error has occurred because of conflicting declarations. This message states the type of the identifier in the redeclarations. Recovery: No recovery is necessary if this result was intended. Change the types in the declarations to be compatible, if necessary. ═══ 19.70. EDC0146 ═══ Function has return type &1. Recovery: No recovery is necessary if this result was intended. Change the return type if necessary. ═══ 19.71. EDC0147 ═══ Argument has type &1. The argument type in the function call conflicts with the parameter in the function prototype. This message states the type of the argument. Recovery: No recovery is necessary if this result was intended. Change the argument types to be compatible, if necessary. ═══ 19.72. EDC0148 ═══ Expression has type &1. Recovery: Informational message. No recovery is necessary if this result was intended. ═══ 19.73. EDC0149 ═══ Operation not allowed with enum that is not defined. The sizeof or cast operator cannot be used with an enum that is not defined. Recovery: Define the enum. ═══ 19.74. EDC0150 ═══ The number of initializers cannot be greater than the number of elements. Too many initializers were found in the initializer list for the indicated declaration. Recovery: Check the number of initializers. Check the closing brace at the end of the initializer list to ensure that it has been positioned correctly. ═══ 19.75. EDC0151 ═══ The initializer must be a constant expression. The initializers for identifiers of static storage duration, or for identifiers of an array, structure, or union type must be constant expressions. Recovery: Remove the initialization or change the indicated initializer to a constant expression. ═══ 19.76. EDC0152 ═══ A register array may only be used as the operand to sizeof. The only operator that may be applied to a register array is sizeof. Recovery: Remove the register keyword from the declaration. ═══ 19.77. EDC0153 ═══ An initializer for a static identifier cannot have the automatic storage class. The initializer cannot have an automatic storage class if the identifier being initialized has a static storage class. Recovery: Either change the storage class in the identifier declaration or change the initializer. ═══ 19.78. EDC0158 ═══ After widening, previous declaration has type &1. An error has occurred due to conflicting identifier declarations. This message states the type of the identifier in the current declaration, after the identifier's type has been widened. Recovery: No recovery is necessary if this result was intended. Change the declarations to the same type if necessary. ═══ 19.79. EDC0159 ═══ After widening, redeclaration has type &1. An error has occurred because of conflicting declarations. This message states the type of the identifier in the redeclarations, after the identifier's type has been widened Recovery: No recovery is necessary if this result was intended. Change the types in the declarations to be compatible, if necessary. ═══ 19.80. EDC0166 ═══ A non-lvalue array cannot be subscripted. Subscript operator cannot be used with a non-lvalue array. Recovery: Change the array to an lvalue one. ═══ 19.81. EDC0167 ═══ A non-lvalue array cannot be used in this context. The location of a non-lvalue array may not be referenced. Recovery: Change the array to an lvalue one. ═══ 19.82. EDC0168 ═══ Operation not valid on a function pointer. Subscript operator, additive operator, and prefix and postfix increment and decrement operators cannot be used with an operand of type pointer to function. Recovery: Change the operator or the operand. ═══ 19.83. EDC0170 ═══ A function cannot be initialized. An attempt was made to assign an initial value to a function identifier. Recovery: Remove the assignment operator and the initializer. ═══ 19.84. EDC0171 ═══ A function cannot return a function. A function cannot have a return type of function. Recovery: Return a pointer to the function or specify a different return type. ═══ 19.85. EDC0172 ═══ Function &1 cannot have a storage class of auto or register. Recovery: Remove the storage class specifier for the function identifier, or change it to either extern or static. ═══ 19.86. EDC0173 ═══ A function cannot be a member of a struct or union. Recovery: Use a pointer to the function or remove the function from the member list. ═══ 19.87. EDC0174 ═══ A function cannot be an element of an array. Recovery: Use a pointer to the function, or change the type of the element. ═══ 19.88. EDC0175 ═══ A function cannot return a &1 qualified type. The const or volatile qualifier cannot be used to qualify a function's return type. Recovery: Remove the qualifier or return a pointer to the qualified type. ═══ 19.89. EDC0176 ═══ Return type must be compatible with the declaration of function &1. The return statement of the function tries to return a structure or a union type that is not compatible with the return type specified in the function declaration/definition. The type of a structure or union is represented by its tag. Two structures have compatible types if both have been declared with the same structure tag. Two unions have compatible types if both have been declared with the same union tag. However, tags are scope sensitive. Even if two tag names and their member lists are identical, if their definitions are located in different scopes, the types associated with these tags are different. Recovery: Ensure that the same tag (in the same scope) is used in the function declaration/definition, as well as in the declaration/definition of the value specified on the return statement, ═══ 19.90. EDC0177 ═══ A function declared to return void cannot return a value. When a function is declared to have a void return type, the return statement of the function cannot return any value. An attempt was made to return a value in a function that was declared/defined with a void return type. Recovery: Change the declaration to specify the return type or do not return a value. ═══ 19.91. EDC0178 ═══ A function cannot return an array. Recovery: Return a pointer to the array or specify a different return type. ═══ 19.92. EDC0179 ═══ The function &1 cannot be redefined. It is not valid to define a function more than once. Do not confuse function definitions and function declarations. A declaration describes the return type of the function. A definition is a declaration followed by the code that is to be executed when the function is called (the code portion is called the function body). Only one definition per function is allowed. Recovery: Remove all extra definitions or change the name of the function. ═══ 19.93. EDC0180 ═══ The static function &1 is referenced but is not defined in this file. A static function was declared and referenced in this file. The definition of the function was not found before the end of the file. When a function is declared to be static, the function definition must appear in the same file. Recovery: Define the function or remove the static storage class. ═══ 19.94. EDC0181 ═══ The struct, union, or enum tag &1 cannot be redefined. A struct or union tag is defined when it is declared with the list describing the name and type of its members. An enum tag is defined when it is declared with the list of its enumeration constants. It is not valid to define a struct, union, or enum tag more than once in the same scope. Recovery: Remove all extra definitions or rename the tag. ═══ 19.95. EDC0183 ═══ An argument cannot be an incomplete struct or union. The argument has an incomplete struct or union type. A structure or union is incomplete when the definition of the tag (i.e. when the number and the type of its members) has not been specified. It is not valid to pass arguments of incomplete type to a function. Recovery: Use a pointer to the incomplete type or define the type before using it. ═══ 19.96. EDC0184 ═══ An argument cannot have type void. The indicated parameter has type void. A parameter of type void cannot be passed on a function call. Recovery: Use a pointer to void or cast the type of the argument. ═══ 19.97. EDC0185 ═══ Function &1 has not been prototyped prior to use. A prototype declaration of the function specifying the number and type of the parameters was not found before the function was used. Errors may occur if the function call does not respect the function definition. Option: /Wpro Recovery: Include a prototype declaration of the function before calling it. ═══ 19.98. EDC0187 ═══ The declaration or definition of the function is not valid. The compiler cannot read the declaration. It assumes that the function declaration was not valid. The return type or the parameters may have been specified incorrectly. Recovery: Check for incorrect spelling or missing parentheses. ═══ 19.99. EDC0189 ═══ The return type of the function main must have type int. Recovery: Change the return type of function main to int. ═══ 19.100. EDC0190 ═══ A switch expression must have integral type. The controlling expression in a switch statement must have integral type. Valid integral types include: char, signed and unsigned int, and enum. Recovery: Change the expression. ═══ 19.101. EDC0191 ═══ A case label must be a constant integral expression. The expression in the case statement must be a constant integral expression. Valid integral expressions are: char, signed and unsigned int, and enum. Recovery: Change the expression. ═══ 19.102. EDC0192 ═══ The case label cannot be a duplicate of the case label on line &1. Two case labels in the same switch statement cannot evaluate to the same integer value. Recovery: Change one of the labels. ═══ 19.103. EDC0193 ═══ A default case label cannot be placed outside a switch statement. Recovery: Remove the default case label, or place it inside a switch statement. Check for misplaced braces on a previous switch statement. ═══ 19.104. EDC0194 ═══ A switch statement cannot contain more than one default statement. Recovery: Remove one of the default statements. ═══ 19.105. EDC0195 ═══ A case statement cannot be placed outside a switch statement. Recovery: Remove the case statement, or place it within a switch statement group. Check for misplaced braces on the previous switch statement. ═══ 19.106. EDC0196 ═══ The case label evaluates to integer value &1. An error occurred due to conflicting case labels. This message states the value of the case labels. Recovery: Change the case label if necessary. ═══ 19.107. EDC0197 ═══ The linkage of main must be either _System or _Optlink. Recovery: Change the linkage of function main to _System or _Optlink. ═══ 19.108. EDC0198 ═══ If the operands are pointers they must point to compatible object or incomplete types. If both operands of a relational operator are pointers, they must point to qualified or unqualified versions of compatible object or incomplete types. Pointers to functions are not allowed. Recovery: Change the operands. ═══ 19.109. EDC0200 ═══ A break statement cannot be placed outside a while, do, for or switch statement. Recovery: Remove the break statement or place it inside a while, do, for or switch statement. Check for misplaced braces on a previous statement. ═══ 19.110. EDC0201 ═══ A continue statement cannot be placed outside a while, do or for loop. Recovery: Remove the continue statement or place it inside a while, do or for loop. Check for misplaced braces on a previous loop. ═══ 19.111. EDC0220 ═══ Only arrays and pointers to object types can be subscripted. An attempt was made to subscript an identifier that was not an array or a pointer to an object type. Recovery: Remove the subscripts or change the identifier. ═══ 19.112. EDC0221 ═══ Array size must be a positive constant integral expression. The array size declared is not valid. If compilation continues, the compiler will assume that the array has size 1. Recovery: Make the array size a positive constant integral expression. ═══ 19.113. EDC0222 ═══ Arrays cannot be redeclared with a different size. Recovery: Make the size consistent with the previous declaration or remove one of the array declarations. ═══ 19.114. EDC0223 ═══ All array dimensions except the first must be specified. Only the first dimension of an initialized array may be unspecified. All the other dimensions must be specified on the declaration. Recovery: Specify all the other dimensions in the array declaration. ═══ 19.115. EDC0224 ═══ All dimensions must be specified for array definitions. All the dimensions of arrays of automatic or static storage class must be specified on the declaration. If the declaration of the automatic or static array provides an initialization, the first dimension may be unspecified because the initialization will determine the size needed. Recovery: Specify all of the dimensions in the array declaration. ═══ 19.116. EDC0225 ═══ Arrays that are members must have all dimensions specified. Arrays that are struct or union members must have all dimensions specified in the array declaration. Recovery: Specify all of the dimensions in the array declaration. ═══ 19.117. EDC0226 ═══ The parameter lists of the function pointers are not compatible. In assignment or initialization of function pointer, the parameter lists of the function pointers must have compatible type. Recovery: Ensure that the parameter lists of the function pointers are compatible. ═══ 19.118. EDC0227 ═══ The return types of the function pointers are not compatible. In assignment or initialization of function pointer, the return types of the function pointers must have compatible type. Recovery: Ensure that the return types of the function pointers are compatible. ═══ 19.119. EDC0228 ═══ The linkage types of the function pointers are not compatible. In assignment or initialization of function pointers, the linkage types of the function pointers must be compatible. Recovery: Ensure that the linkage types of the function pointers are compatible. ═══ 19.120. EDC0240 ═══ Escape sequence is out of range for character representation. Character constants specified in an escape sequence exceeded the decimal value of 255, or the octal equivalent of 377, or the hexadecimal equivalent of FF. Recovery: Change the escape sequence so that the value does not exceed the maximum value. ═══ 19.121. EDC0242 ═══ Nesting cannot exceed the maximum limit &1. The internal compiler limit of &1 nested #include files was exceeded. Recovery: Remove the nesting by putting all of the #include files at the same level, or reduce the number of nesting levels. ═══ 19.122. EDC0244 ═══ External name &1 has been truncated to &2. The external object has a name &1 which exceeds the limit and has been truncated to the name &2. Option: /Wtru Recovery: Change the name if necessary. ═══ 19.123. EDC0246 ═══ Floating point constant is out of range. The compiler detected a floating-point overflow either in scanning a floating-point constant, or in performing constant arithmetic folding. Recovery: Change the floating-point constant so that it does not exceed the maximum value. ═══ 19.124. EDC0247 ═══ Virtual storage exceeded. The compiler ran out of memory trying to compile the file. This sometimes happens with large files or programs with large functions. Note that very large programs limit the amount of optimization that can be done. Recovery: Shut down any large processes that are running, ensure your swap path is large enough, turn off optimization, and redefine your virtual storage to a larger size. You can also divide the file into several small sections or shorten the function. ═══ 19.125. EDC0248 ═══ External name &1 cannot be redefined. An external name cannot be redefined. External names can have up to 255 significant characters, and can be upper or lowercase. Because the number of significant characters can be limited using the /H option, the compiler may recognize two names as identical although they are not. For example, when /H3 is specified, the identifiers ABCD and ABCE are considered identical because only the first three letters are significant. Recovery: Remove one of the definitions, change one of the names, or change the number specified on the /H option. ═══ 19.126. EDC0249 ═══ The number of errors exceeds the limit. The number of errors has exceeded the number specified on the /N option. Recovery: Fix the errors or increase the error limit on the /N option. ═══ 19.127. EDC0250 ═══ The maximum number of errors for one line has been exceeded. The compiler is unable to specify the location of each error in the listing because there are too many errors on one line. Recovery: Correct the errors or split the source line into multiple lines. ═══ 19.128. EDC0251 ═══ The physical size of an array is too large. The compiler cannot handle any size which is too large to be represented internally. Recovery: Reduce the size of the array. ═══ 19.129. EDC0252 ═══ The physical size of a struct or union is too large. The compiler cannot handle any size which is too large to be represented internally. Recovery: Reduce the sizes of the struct or union members. ═══ 19.130. EDC0260 ═══ Declaration cannot specify multiple sign type specifiers. A declaration can specify a signed or unsigned type, but not both. Recovery: Keep only one sign type specifier. ═══ 19.131. EDC0261 ═══ Declaration cannot specify multiple length type specifiers. A declaration can specify a long or short type, but not both. Recovery: Keep only one length type specifier. ═══ 19.132. EDC0262 ═══ Declaration cannot specify multiple type specifiers. A declaration can specify only one data type specifier. Valid specifiers include: char, int, float and double. Recovery: Keep only one type specifier. ═══ 19.133. EDC0263 ═══ Declaration cannot specify multiple linkage specifiers. A declaration can specify only one linkage type. Valid linkage types include: _System, _Optlink, _Far16, _Cdecl, _Pascal, and _Fastcall. Recovery: Use only one linkage type, or _Far16 with one of _Cdecl, _Pascal or _Fastcall. ═══ 19.134. EDC0265 ═══ Declaration cannot specify multiple storage class specifiers. A declaration can specify only one storage class. Valid storage classes include: auto, static, extern, register and typedef. Recovery: Use only one storage class specifier. ═══ 19.135. EDC0266 ═══ The &1 type specifier cannot be used with float or double. The type specifiers signed, unsigned and short cannot be used with type float or double. Recovery: Ensure that the appropriate type is used, and remove the incorrect type specifier from the declaration. Use type long double if a larger identifier is required. ═══ 19.136. EDC0268 ═══ The long type specifier cannot be used with float. Recovery: Remove the long type specifier or use double instead of float. ═══ 19.137. EDC0269 ═══ The long or short type specifier cannot be used with char. Recovery: Remove the length type specifier. Use type int or short int if a larger identifier is required. ═══ 19.138. EDC0270 ═══ The &1 type specifier cannot be used with void. No other type specifier can be used with type void. Recovery: Remove the type specifier or the void. ═══ 19.139. EDC0272 ═══ The &1 type specifier cannot be used with struct, union or enum. No other type specifiers can be used with struct, union or enum. Recovery: Remove the type specifier. ═══ 19.140. EDC0274 ═══ The &1 type specifier cannot be used for variables declared with a typedef. No other type specifiers can be used for variables declared with a typedef. Recovery: Remove the type specifier or the typedef. ═══ 19.141. EDC0275 ═══ The predefined macro &1 is being redefined. The macro &1 is predefined. Predefined macros should not be redefined. Recovery: Ensure that you really do want to redefine the macro. ═══ 19.142. EDC0276 ═══ The predefined macro &1 is being undefined. The macro &1 is predefined. Predefined macros should not be undefined. Recovery: Ensure that you really do want to undefine the macro. ═══ 19.143. EDC0277 ═══ _Packed can only qualify a struct or union. Recovery: Remove the _Packed specifier from the declaration/definition, or ensure it qualifies a struct or union. ═══ 19.144. EDC0278 ═══ Declaration cannot specify multiple &1 specifiers. Recovery: Ensure that only one &1 specifier is used. ═══ 19.145. EDC0279 ═══ _Seg16 can only qualify a pointer type. Recovery: Remove the _Seg16 specifier from the declaration/definition, or ensure it qualifies a pointer. ═══ 19.146. EDC0280 ═══ The predefined macro &1 cannot be redefined. An attempt to redefine a predefined macro by using either #define in your code or /D on the command line was encountered. Certain predifined macros cannot be redefined. Recovery: Remove the #define or /D. ═══ 19.147. EDC0281 ═══ The identifier &1 cannot be redeclared. Only external objects can be redeclared. Recovery: Delete or change the name of the extra declaration. ═══ 19.148. EDC0282 ═══ The struct member &1 cannot be redeclared. The same struct member cannot be redeclared. To redeclare the structure itself, the same tag must be used. Recovery: Delete or change the name of the extra declaration. ═══ 19.149. EDC0283 ═══ The tag &1 cannot be redefined as a tag of another type. The tag is already associated with another struct, union or enum type. Recovery: Delete or rename the tag. ═══ 19.150. EDC0284 ═══ The label &1 cannot be redefined. The label has already been defined in the function (a label of the same name followed by a colon and a section of code already appeared in the same function). It is not valid to redefine a label. Recovery: Change the name of one label. ═══ 19.151. EDC0285 ═══ The predefined macro &1 cannot be undefined. You tried to undefine a predefined macro by using either #undef in your code or /U on the command line. You are not allowed to undefine certain predefined macros. Recovery: Remove the #undef or /U. ═══ 19.152. EDC0286 ═══ The redeclaration cannot specify a different storage class. The redeclaration, including type qualifiers (const, volatile), must be identical to the first declaration. Redeclaring basic types: The type (which includes the type specifiers and the length and sign adjectives) and the type qualifiers (const, volatile) must be the same. Redeclaring functions: The return type with its type qualifiers has to be the same. If the function has been prototyped, the prototyped redeclarations must have an identical parameter list (the number and type of the parameters must be the same). Redeclaring pointers: They have to point at the same type (including the type qualifiers). Redeclaring arrays: Their members must be of the same type (including the type qualifiers). The array size must be the same. Redeclaring enumerations, structures, and unions: They must have the same tag. Recovery: Ensure that the storage class of the subsequent declarations matches the original declaration or remove one of the declarations. ═══ 19.153. EDC0287 ═══ The goto label is not defined in function &1. The goto label is referenced but not defined in the function. The label definition (label followed by a colon and a section of code) must appear in the same function that references the label. Recovery: Define the goto label in the function or remove the reference. ═══ 19.154. EDC0288 ═══ The void type can only be used with functions and pointers. The type void can only be used as the return type or parameter list of a function, or with a pointer indicating the type to which it is pointed. No other object can be of type void. Recovery: Ensure that the declaration uses type void correctly. ═══ 19.155. EDC0289 ═══ The typedef name &1 cannot be redefined. Redefinitions of typedef names are not allowed even if the definitions occur at file scope with identical type specifiers. Recovery: Remove identical definitions or, for a new definition, rename the typedef. ═══ 19.156. EDC0291 ═══ The &1 storage class cannot be used with external identifier &2. Identifiers may only be declared with auto or register storage class if they are declared inside a block. Recovery: Remove the storage class specifier or change the scope of the identifier so that it is no longer at file scope. ═══ 19.157. EDC0292 ═══ The block scope declaration of object &1 must be compatible with its external declaration. This block scope redeclaration of the external object is incompatible with the previous external declaration. Recovery: Ensure that the block scope declaration is identical with the file scope declaration, or remove one of the declarations. ═══ 19.158. EDC0293 ═══ The static storage class cannot be used with functions declared at block scope. Recovery: Place the declaration of the static function at file scope, or remove the storage class specifier. ═══ 19.159. EDC0294 ═══ The typedef storage class cannot be used on function definitions. The typedef storage class can only be used with function declarations to declare a function type. A typedef name cannot carry the information of a function definition; it cannot specify the part of code to be executed when a function is called. Recovery: Remove the typedef storage class. ═══ 19.160. EDC0297 ═══ Only functions or typedefs of functions can be given a linkage type. Either a #pragma linkage or a linkage keyword has been applied to an identifier which does not correspond to a function type or a typedef to a function type. Recovery: If the error applies to an identifier used on a #pragma linkage directive, then change the name specified on the #pragma linkage directive or remove the directive. If the error applies to an identifier used with a linkage keyword, then remove the keyword. ═══ 19.161. EDC0298 ═══ A #pragma &1 directive was previously specified for the object &2. More than one #pragma linkage directive was specified for the same object. Recovery: Remove the extra #pragma linkage directives. ═══ 19.162. EDC0299 ═══ A map name was previously given to the object &1. An object can map to only one name. Option: See map for more information on #pragma map. Recovery: Remove the extra #pragma map directives. ═══ 19.163. EDC0300 ═══ The floating point constant is not valid. See Floating-Point Constants for a description of a floating-point constant. Recovery: Ensure that the floating-point constant does not contain any characters that are not valid. ═══ 19.164. EDC0301 ═══ A const qualified object cannot be modified. The value of a const cannot be changed. Increment/decrement can only be performed on objects that are not constants. Recovery: Either do not declare the object with the const type qualifier, or do not use the object in an increment/decrement operation. ═══ 19.165. EDC0303 ═══ Only function names can be specified in a #pragma &1 directive. Recovery: Ensure that the spelling of the function name is correct and that the function name has been declared before you use it in this directive. ═══ 19.166. EDC0306 ═══ Only #pragma pit(*, ...) is allowed with the /Tp- option. ═══ 19.167. EDC0307 ═══ The floating-point constant is too large and is converted to an infinity. The magnitude of the floating-point constant specified is too large. The number is converted into positive or negative infinity, depending on the sign of the number. Recovery: Ensure this is what was intended. ═══ 19.168. EDC0308 ═══ An enum constant must be an integral constant expression that has a value representable as an int. If an enum constant is initialized in the definition of an enum tag, the value that the constant is initialized to must be an integral expression that has a value representable as an int. Recovery: Remove the initial value, or ensure that the initial value is an integral constant expression that has a value representable as an int. ═══ 19.169. EDC0309 ═══ A linkage type must appear to the left of the identifier to which it applies. A declaration has been discovered which resembles int foo _System (); The keyword _System must appear immediately to the left of the identifier foo. Recovery: Move the linkage descriptors to the left of the identifier. ═══ 19.170. EDC0310 ═══ The typedef name &1 has already been given the same definition. The typedef name has already been declared with the same type as this declaration gives it. Redeclaring a typedef at the same scope is not portable and might not be supported by other compilers. Option: /Wpor Recovery: Remove identical definitions or, for a new definition, rename the typedef. ═══ 19.171. EDC0311 ═══ #pragma &1 overrides command line option &2. The option set in the #pragma statement conflicts with the option set in the command line. Recovery: Remove or change the #pragma statement or the command line option. ═══ 19.172. EDC0312 ═══ Value &1 specified in #pragma &2 is out of range. In #pragma margins and #pragma sequence, the value specified for the right margin or sequence column must be greater than or equal to the value specified for the left margin or sequence column. The values specified for the left and right margins or sequence columns must lie in the range Option: 1 to 65535. Recovery: Change the value specified for the left or right margin or sequence column. ═══ 19.173. EDC0321 ═══ Redeclaration has different number of parameters from the previous declaration. The prototyped redeclaration of the function is not correct. The redeclaration must specify the same number of parameters as the previous declaration. Recovery: Make the redeclaration consistent with the original declaration. ═══ 19.174. EDC0322 ═══ Type of the parameter &1 cannot conflict with previous declaration of function &2. The type of this parameter is incompatible with the type of the corresponding parameter in the previous declaration of the function. Recovery: Ensure that the subsequent declaration or function call matches the prototype in both the number and type of parameters. If the parameter in the prototype is an incomplete struct or union tag, declare the incomplete tag at file scope before the function is prototyped. ═══ 19.175. EDC0323 ═══ Redeclaration cannot specify fewer parameters before ellipsis than the previous declaration. The prototyped redeclaration of the function is not correct. Fewer parameters appear before the ellipsis in this function redeclaration than the previous declaration. Recovery: Ensure that the redeclaration is consistent with the previous declaration. ═══ 19.176. EDC0324 ═══ The void type specifier cannot be used with other type specifiers. When void is used in the parameter list of a prototyped function declaration, it indicates that the function does not expect any parameters. Therefore, if void is used in a prototyped declaration, it must be the only type descriptor in the parameter list and must not appear more than once in the list. Recovery: If the function does not require any parameters, use void only once in the parameter list. If the function requires parameters, remove void from the parameter prototype list. ═══ 19.177. EDC0325 ═══ The type of the parameters must be specified in a prototype. A prototype specifies the number and the type of the parameters that a function requires. A prototype that does not specify the type of the parameters is not correct, for example, Option: fred(a,b); Recovery: Specify the type of the parameters in the function prototype. ═══ 19.178. EDC0326 ═══ The only storage class that can be used with parameters is register. Recovery: Remove the storage class specified in the parameter declaration or use the register storage class. ═══ 19.179. EDC0327 ═══ Redeclarations and function calls must be compatible with prototype. The number or the type of the parameters (or both) on the call does not agree with the specification given in the function prototype declaration. Recovery: Make the call consistent with the declaration. ═══ 19.180. EDC0328 ═══ The function call cannot have more arguments than the prototype specifies. The function call is not valid. There are more arguments in this function call than there were parameters specified in the function declaration. Recovery: Make the call consistent with the declaration. ═══ 19.181. EDC0329 ═══ Object &1 must be specified in the parameter list for function &2. For function definitions that do not use the prototype style, a list of parameter names usually appears between the parentheses following the function name. A list of declarations that indicates the type of the parameters follows. In this case, the declaration of an object that was not listed between the parentheses was found in the parameter declaration list. Recovery: Ensure that the declaration list only specified parameters that appear between the parentheses of the function. ═══ 19.182. EDC0330 ═══ A parameter cannot be declared when function &1 parentheses are empty. For function definitions that do not use the prototype style, a list of parameter names usually appears between parentheses following the function name. A list of declarations that indicates the type of the parameters follows. In this case, objects are declared in the parameter declaration list but no parameter appeared between the function parentheses. Recovery: Ensure that the declaration list only specifies parameters that were listed between the function parentheses. ═══ 19.183. EDC0331 ═══ Parentheses must appear in the declaration of function &1. The syntax of the declaration is not correct. The compiler assumes it is the declaration of a function in which the parentheses surrounding the parameters are missing. Recovery: Check the syntax of the declaration. Ensure the object name and type are properly specified. Check for incorrect spelling or missing parentheses. ═══ 19.184. EDC0333 ═══ The parameters in the definition of the function &1 must be named. For function definitions, all the parameters in the parameter list must be named. It is not valid to specify only the parameter's type in a function definition head. Recovery: Name the parameters in the parameter list. ═══ 19.185. EDC0334 ═══ External identifier &1 cannot be initialized more than once. Recovery: Check the previous declarations of the object. Ensure that only one declaration specifies an initializer. ═══ 19.186. EDC0335 ═══ The declarations of the function &1 must be consistent in their use of the ellipsis. If an ellipsis is used in a function declaration, the ellipsis must be present in all the function redeclarations. If no ellipsis is used in a function declaration, the following redeclarations cannot specify an ellipsis. Any redeclaration that does not use the ellipsis consistently is not correct. Recovery: Make the redeclaration consistent with the previous declaration. ═══ 19.187. EDC0337 ═══ Declaration list cannot appear when parameters in parentheses are prototyped. For function definitions that do not use the prototype style, a list of parameter names usually appears between parentheses following the function name. A list of declarations that indicates the type of parameters follows. In this case, the parameters between the parentheses are prototyped. These two styles of declaration cannot be mixed. Recovery: Remove either the function declaration list or the type given to the parameters in the function parentheses. ═══ 19.188. EDC0338 ═══ Prototype &1 must contain widened types if prototype and nonprototype declarations are mixed. Nonprototype function declarations, popularly known as K&R prototypes, only specify the function return type. The function parentheses are empty; no information about the parameters is given. Nonprototype function definitions specify a list of parameter names appearing between the function parentheses followed by a list of declarations (located between the parentheses and the opening left brace of the function) that indicates the type of the parameters. A nonprototype function definition is also known as a K&R function definition. A prototype function declaration or definition specifies the type and the number of the parameters in the parameter declaration list that appears inside the function parenthesis. A prototype function declaration is better known as an ANSI prototype, and a prototype function definition is better known as an ANSI function definition. When the nonprototype function declarations/definitions are mixed with prototype declarations, the type of each prototype parameter must be compatible with the type that results from the application of the default argument promotions. Most types are already compatible with their default argument promotions. The only ones that aren't are char, short, and float. Their promoted versions are, respectively, int, int, and double. This message can occur in several situations. The most common is when mixing ANSI prototypes with K&R function definitions. If a function is defined using a K&R-style header, then its prototype, if present, must specify widened versions of the parameter types. Here is an example. int function( short ); int function( x ) short x; { } This is not valid because the function has a K&R-style definition and the prototype does not specify the widened version of the parameter. To be correct, the prototype should be int function( int ); becuase int is the widened version of short. Another possible solution is to change the function definition to use ANSI syntax. This particular example would be changed to int function( short ); int function( short x ) { } This second solution is preferable, but either solution is equally valid. Recovery: Give a promoted type to the parameter in the prototype function declaration. ═══ 19.189. EDC0339 ═══ The function cannot be redeclared with a different linkage type. The redeclaration of this function cannot have a different linkage type than the previous declaration. The function could have been given a linkage type through a #pragma linkage directive, a typedef, or via a previous declaration. Recovery: Ensure that the linkage type of the subsequent declarations matches the original declaration or remove one of the declarations. ═══ 19.190. EDC0340 ═══ The enum cannot be packed to the requested size of &1. /Su1 or /Su2 was specified, but the largest member of the enum will not fit within a one or two byte integer. It will be packed into the smallest integral type that can contain all members. Recovery: Ignore warning, or specify a larger size via the /Su option. ═══ 19.191. EDC0347 ═══ Syntax error: possible missing &1 or &2. A syntax error has occurred. This message lists the tokens that the parser expected and did not find. Recovery: Correct the syntax error and compile again. ═══ 19.192. EDC0348 ═══ Syntax error: possible missing &1. A syntax error has occurred. This message lists the tokens that the parser expected and did not find. Recovery: Correct the syntax error and compile again. ═══ 19.193. EDC0349 ═══ Unexpected text &1 ignored. A syntax error has occurred. This message lists the tokens that were discarded by the parser when it tried to recover from the syntax error. Recovery: Correct the syntax error and compile again. ═══ 19.194. EDC0350 ═══ Syntax error. See the other sections in this document for a complete description of C syntax rules. Recovery: Correct the syntax error and compile again. ═══ 19.195. EDC0351 ═══ &1. General error message. Recovery: General error message. ═══ 19.196. EDC0354 ═══ &1. General warning message. Recovery: General warning message. ═══ 19.197. EDC0355 ═══ &1. General informational message. Recovery: General informational message. ═══ 19.198. EDC0356 ═══ A constant expression cannot contain a comma operator. Recovery: Modify the constant expression to remove the comma operator. ═══ 19.199. EDC0370 ═══ Operand of offsetof macro must be a struct or a union. The first operand of the offsetof macro must be a structure or union type. Recovery: Change the operand. ═══ 19.200. EDC0371 ═══ The dot operator cannot be applied to an incomplete struct or union. A structure or union is incomplete when the definition of its tag has not been specified. A struct or union tag is undefined when the list describing the name and type of its members has not been specified. Recovery: Give a definition of the tag before the operator is applied to the structure. ═══ 19.201. EDC0372 ═══ The arrow operator cannot be applied to an incomplete struct or union. A structure or union is incomplete when the definition of its tag has not been specified. A struct or union tag is undefined when the list describing the name and type of its members has not been specified. Recovery: Give a definition of the tag before the operator is applied to the structure. ═══ 19.202. EDC0397 ═══ Macro argument list is not complete. Either the arguments are not fully specified or a comma or closing parenthesis is missing. Recovery: Complete the specification of the macro argument list. ═══ 19.203. EDC0398 ═══ The pragma &1 directive for function &2 is not valid. The pragma inline and noinline directives must be issued at file scope in order to take effect. Recovery: Issue the pragma directive at file scope. ═══ 19.204. EDC0399 ═══ A character constant must contain at least one character. Recovery: Put at least one character inside the pair of single quotation marks. ═══ 19.205. EDC0400 ═══ String literals must end before the source line unless the continuation symbol is used. String literals must end before the end of the source line. String literals can be constructed which are longer than one line by using the line continuation sequence (backslash (\) at the end of the line) or by using the concatenation of adjacent string literals. Recovery: Either end the string with a quotation mark or use the continuation sequence. ═══ 19.206. EDC0401 ═══ The character is not valid. A character not in the C source character set has been encountered. Recovery: Remove the character. Check the syntax. ═══ 19.207. EDC0403 ═══ The #line directive must specify a string literal or a new-line character. The integer value in the #line directive must be followed by a string literal or the end of the line. Recovery: Correct the #line directive. ═══ 19.208. EDC0404 ═══ End of file was reached before end of comment that started on line &1. A comment that was not terminated has been detected. The beginning of the comment was on the specified line. Recovery: End the comment before the file ends. ═══ 19.209. EDC0405 ═══ A new-line character is required. A character sequence was encountered when the preprocessor required a new-line character. ═══ 19.210. EDC0406 ═══ Preprocessing token # must be followed by a parameter. The # preprocessor operator may only be applied to a macro parameter. Recovery: Place a parameter after the # token, or remove the token. ═══ 19.211. EDC0407 ═══ The #include directive is not valid. The #include file specifier is missing or not valid. Recovery: Check the spelling and syntax of the #include file path. ═══ 19.212. EDC0408 ═══ A #if, #elif, #ifdef or #ifndef block must end with a #endif. Recovery: End the conditional preprocessor statements with a #endif. ═══ 19.213. EDC0409 ═══ A macro name on #&1 directive is expected. Recovery: Ensure that a macro name follows the #define, #undef, #ifdef, or #ifndef preprocessor directive. ═══ 19.214. EDC0410 ═══ A #&1 can only appear within a #if, #elif, #ifdef or #ifndef block. Recovery: Delete the #elif or #else statement, or place it within a conditional preprocessor block. Check for misplaced braces. ═══ 19.215. EDC0412 ═══ A #endif must follow a #if, #elif, #ifdef or #ifndef block. Recovery: Delete the #endif statement, or place it after a conditional preprocessor block. ═══ 19.216. EDC0413 ═══ #elif cannot follow #else. The #elif directive may not follow a #else directive within a #if, #elif, #ifdef or #ifndef block. Recovery: Remove the #elif or the #else. ═══ 19.217. EDC0414 ═══ End of file is not expected. The end of the source file has been encountered prematurely. Recovery: Check for misplaced braces. ═══ 19.218. EDC0415 ═══ Text is too long. The specified token is too long to be processed. This condition arises when a numeric literal with many leading zeros or a floating point literal with many trailing digits in the fraction is coded. Recovery: Create a shorter token. ═══ 19.219. EDC0416 ═══ The integer constant suffix is not valid. The integer constant has a suffix letter that is not recognized as a valid suffix. ═══ 19.220. EDC0417 ═══ Integer constant is out of range. The specified constant is too large to be represented by an unsigned long int. Recovery: The constant integer must have a value less than 4294967296. ═══ 19.221. EDC0418 ═══ Escape character &1 is not valid and is ignored. An escape sequence that is not valid has been encountered in a string literal or a character literal. It is replaced by the character following the backslash (\). Recovery: Change or remove the escape sequence. ═══ 19.222. EDC0419 ═══ A character literal must end before the end of a line. Character literals must be terminated before the end of the source line. Recovery: End the character literal before the end of the line. Check for misplaced quotation marks. ═══ 19.223. EDC0420 ═══ The ## operator cannot appear first or last in the macro replacement list. The ## operator must be preceded and followed by valid tokens in the macro replacement list. ═══ 19.224. EDC0421 ═══ The macro parameter list is incorrect. The macro parameter list must be empty, contain a single identifier, or contain a list of identifiers separated by commas. Recovery: Correct the parameter list. ═══ 19.225. EDC0422 ═══ Parameter &1 cannot be redefined in the macro parameter list. The identifiers in the macro parameter list must be distinct. Recovery: Change the identifier name in the parameter list. ═══ 19.226. EDC0423 ═══ Macro name &1 cannot be redefined. A macro may be defined multiple times only if the definitions are identical except for white space. Recovery: Change the macro definition to be identical to the preceding one, or remove it. ═══ 19.227. EDC0424 ═══ The expression on the #if or #elif directive is not a valid constant expression. Recovery: Replace the expression that controls #if or #elif by a constant integral expression. ═══ 19.228. EDC0425 ═══ Parameter list must specify same number of parameters as required by macro definition. The number of arguments specified on a macro invocation is different from the number of parameters required for the macro. Recovery: Make the number of arguments consistent with the macro definition. ═══ 19.229. EDC0426 ═══ The #error text is too long. The text specified for the #error directive is too long to be processed. The maximum length allowed for #error text is 4096 characters. Recovery: Specify a shorter message. ═══ 19.230. EDC0427 ═══ #error &1 This is the message issued by the #error directive. Recovery: Because this is a user-created message, the recovery depends on the nature of the error. ═══ 19.231. EDC0428 ═══ A preprocessing directive must end before the end of a line. The end of line has been encountered while scanning a preprocessing directive. ═══ 19.232. EDC0429 ═══ String literal cannot exceed maximum length of 4096. A string constant of length greater than 4096 characters was encountered. Recovery: Specify a shorter string literal. ═══ 19.233. EDC0430 ═══ The preprocessing directive &1 is not valid. An unrecognized preprocessing directive has been encountered. Recovery: Check the spelling and syntax or remove the directive that is not valid. ═══ 19.234. EDC0431 ═══ The end of a #include file was encountered before the end of the comment. Recovery: End the comment before ending the #include file. Check for misplaced or missing punctuation. ═══ 19.235. EDC0432 ═══ The end of file was encountered immediately after a continuation line. Recovery: Remove the continuation character from the last line of the file, or add code after the continuation character. ═══ 19.236. EDC0433 ═══ #line value too large. Recovery: Ensure that the #line value does not exceed the maximum value (32767) for short integers. ═══ 19.237. EDC0434 ═══ &1 value must contain only decimal digits. A non-numeric character was encountered in the &1 value. Recovery: Check the syntax of the value given. ═══ 19.238. EDC0435 ═══ A valid wide character must not have 0x00 as its second byte. Recovery: Change the value of the second byte of the wide character. ═══ 19.239. EDC0437 ═══ A character string literal cannot be concatenated with a wide string literal. A string that has a prefix L cannot be concatenated with a string that is not prefixed. Recovery: Check the syntax of the value given. ═══ 19.240. EDC0438 ═══ An error was detected in #pragma &1. For a description of the syntax for #pragma directives, see #pragma of this book. Recovery: Check the syntax of the #pragma directive. ═══ 19.241. EDC0439 ═══ Option &1 on #pragma &2 is not supported. For a list of all valid options for #pragma directives, see #pragma of this book. Recovery: Ensure the #pragma syntax and options are correct. ═══ 19.242. EDC0441 ═══ #pragma &1 is unrecognized and is ignored. An unrecognized #pragma directive was encountered. See #pragma for the list of valid #pragmas available. Recovery: Change or remove the #pragma directive. ═══ 19.243. EDC0442 ═══ Option on #pragma &1 is out of range. The specified #pragma option is not within the range of the valid values. See #pragma for more information on the #pragma directives. Recovery: Change the option or remove the #pragma directive. ═══ 19.244. EDC0443 ═══ #pragma &1 must appear on the first directive before any C code. Recovery: Ensure the indicated #pragma appears on the first directive and before any C code. ═══ 19.245. EDC0444 ═══ The #pragma &1 must appear only once and before any C code. Recovery: Remove all but one of the specified #pragma directives and place the #pragma directive before any C code. ═══ 19.246. EDC0445 ═══ Only one facility ID can appear on all #pragma pit directives in a compilation unit. ═══ 19.247. EDC0449 ═══ A new-line is not expected before the end of the preprocessing directive. A new-line was encountered before the preprocessor directive was complete. Recovery: Ensure the preprocessor directive ends before the end of the line. ═══ 19.248. EDC0450 ═══ Option &1 ignored because option &2 specified. The use of the second option indicated means the first has no effect. For example, the /P option causes the /O option to be ignored because no code will be generated. Recovery: Remove one of the options. ═══ 19.249. EDC0451 ═══ The &1 option has not been completely specified. Refer to Specifying Compiler Options for information on specifying compiler options. Recovery: Complete or remove the option. ═══ 19.250. EDC0452 ═══ Suboption &2 of &1 is not valid. An incorrect suboption of the specified compiler option has been given. See Specifying Compiler Options for more information on compiler options. Recovery: Change or remove the incorrect suboption. ═══ 19.251. EDC0455 ═══ Suboption &2 of &1 is out of range. A suboption of the specified compiler option is not within the range of valid values. See Specifying Compiler Options for more information on compiler options. Recovery: Change or remove the suboption. ═══ 19.252. EDC0456 ═══ Suboptions &2 and &3 of option &1 conflict. Conflicting suboptions of the indicated compiler option have been specified. Recovery: Remove one of the conflicting suboptions. ═══ 19.253. EDC0460 ═══ Macro name &1 must not begin with a numeric character on &2 option. Macro names must begin with an alphabetic character or an underscore. Recovery: Change the macro name. ═══ 19.254. EDC0461 ═══ &1 cannot be defined as a macro on the &2 option. Recovery: Remove the macro definition. ═══ 19.255. EDC0462 ═══ Macro definition on the &1 option is not valid. Recovery: Remove the macro definition or change the macro name. ═══ 19.256. EDC0463 ═══ Option &1 is not valid. An incorrect compiler option has been encountered. See Specifying Compiler Options for valid compiler options. Recovery: Change or remove the option. ═══ 19.257. EDC0464 ═══ Character constant has more than four bytes. A character constant can only have up to four bytes. Option: /Wpor Recovery: Change the character constant to contain four bytes or less. ═══ 19.258. EDC0465 ═══ Unable to open the default file for &1 output. The intermediate file (with a .I extension) could not be opened when the /P option was specified. The directory may be full. Recovery: Delete some files from the directory to free some space. ═══ 19.259. EDC0468 ═══ Macro name &1 on &2 option is already defined. On the /D option a macro may be defined multiple times only if the definitions are identical except for white space. Recovery: Remove all but one of the indicated macro definitions, make them all identical, or change the name of the macro. ═══ 19.260. EDC0469 ═══ Macro name &1 has been truncated to &2 on the &3 option. The length of the macro name on the /D option is greater than the maximum allowed. The name has been truncated. Recovery: Change the macro name if necessary. ═══ 19.261. EDC0470 ═══ Macro name &1 contains characters not valid on the &2 option. Macro names can contain only alphanumeric characters and the underscore character. Recovery: Change the macro name. ═══ 19.262. EDC0472 ═══ Local options following file name have been ignored. Recovery: Remove local options following file name. ═══ 19.263. EDC0473 ═══ Missing source or object file. Recovery: Specify a source or object file. ═══ 19.264. EDC0475 ═══ Option &1 ignored because option &2 is not specified. The second option must be specified for the first to have an effect. For example, to use the /Le option, the /Lf option must also be specified. Recovery: Specify the second option, or remove the first. ═══ 19.265. EDC0479 ═══ A module definition (.DEF) file must be specified to create a DLL. Recovery: Provide a module definition (.DEF) file. ═══ 19.266. EDC0480 ═══ Option &1 requires that &2 be specified. Recovery: Specify option &2 on the command line. ═══ 19.267. EDC0481 ═══ Option &1 is ignored in &2 mode. This compiler option is not supported by &2 mode. See Specifying Compiler Options for all &2 options. Recovery: Change or remove the options. ═══ 19.268. EDC0482 ═══ Option /Ol specified, but no source or intermediate file provided. Recovery: Specify a source or intermedicate file. ═══ 19.269. EDC0483 ═══ Unable to find a complete set of intermediate files, .w, .wh and .wi, for &1. Recovery: Ensure that a complete set of intermediate files (.w, .wh, and wi) is existed corresponding to the intermediate file specified on the command (when the compile command is issued). ═══ 19.270. EDC0484 ═══ To specify an intermediate file, use &1.w instead of &1&2. Recovery: Specify the intermediate file with .w extension only. ═══ 19.271. EDC0485 ═══ Cannot declare a pointer to a function with builtin linkage. Recovery: Remove the #pragma linkage or builtin keyword from the declaration of the function. ═══ 19.272. EDC0486 ═══ Cannot expliticly or implicitly take the address of a function with builtin linkage. The address of a builtin function cannot be determined. The compiler does not allow for the declaration of a pointer to a builtin function. Recovery: Remove the #pragma linkage or builtin keyword from the declaration of the function. ═══ 19.273. EDC0487 ═══ Unable to open icc response file &1. Recovery: Ensure file exists. ═══ 19.274. EDC0488 ═══ Nested response files are not supported. Recovery: Remove all the nesting in the response file. ═══ 19.275. EDC0489 ═══ The icc command line specification is not valid. When using a response file on the icc command line, no other parameters are allowed and there must be no space between the '@' sign and the response file name. Recovery: Remove all parameters other than the response file on the command line or remove the space between the '@' sign and the response file name. ═══ 19.276. EDC0490 ═══ Option &1 needs additional listing option to generate a listing. This option only modifies the appearance of a listing; it does not cause a listing to be produced. Recovery: Use this option with one of the other listing file options or the /Fl option to produce a listing. ═══ 19.277. EDC0491 ═══ The compilation cannot continue because Ctrl-Z (0x1A) was encountered in the response file. The Ctrl-Z (0x1A) is interpreted as end-of-file indicator. Any characters following will be lost. Recovery: Remove the Ctrl-Z character (0x1A) from the response file. ═══ 19.278. EDC0501 ═══ Unable to open file for intermediate code. Not able to open intermediate listing file. ═══ 19.279. EDC0503 ═══ Unable to open listing file &1. The source listing file could not be opened. Recovery: Ensure enough disk space is available. ═══ 19.280. EDC0504 ═══ Unable to find #include file &1. The file specified on the #include directive could not be found. Recovery: Ensure the #include file name and the search path are correct. ═══ 19.281. EDC0506 ═══ Unable to find source file &1. Ensure that the name of the file specified on the command line (when the compile command is issued) corresponds to an existing C source file. ═══ 19.282. EDC0517 ═══ &1 value must be an integer constant. Recovery: Change the value to an integer constant. ═══ 19.283. EDC0518 ═══ A line number must be specified on a #line directive. Recovery: Specify a line number on the #line directive. ═══ 19.284. EDC0519 ═══ #line value may not be zero. Recovery: Ensure that the #line value is not zero. ═══ 19.285. EDC0550 ═══ Macro parameter list must end before the end of the line. The list of parameters for a macro on a #define directive did not end before the end of the line. Recovery: End the parameter list before the end of the line. Check that all required continuation lines have been coded. ═══ 19.286. EDC0551 ═══ The #include file header cannot be empty. The #include file header specified is empty. Recovery: Remove the #include directive or ensure that the header is not empty. ═══ 19.287. EDC0553 ═══ Builtin function &1 is unrecognized. ═══ 19.288. EDC0630 ═══ Error in allocating memory for intermediate files. Recovery: Ensure enough memory is available. ═══ 19.289. EDC0631 ═══ Error in allocating disk space for intermediate files. Recovery: Ensure there is enough disk space in the TMP directory. Delete some files from the TMP directory and compile again. ═══ 19.290. EDC0632 ═══ Error in opening intermediate files. Recovery: Ensure there is enough disk space and memory available. ═══ 19.291. EDC0633 ═══ Error in closing intermediate files. Recovery: Restart the system, and compile again. If this problem persists, contact your IBM Service representative. ═══ 19.292. EDC0634 ═══ Error in creating name for intermediate files. Recovery: Restart the system and compile again. If the problem persists, contact your IBM Service Representative. ═══ 19.293. EDC0635 ═══ Error in writing to intermediate files. Recovery: Ensure there is enough disk space and memory available in the TMP directory. ═══ 19.294. EDC0636 ═══ Unable to execute &1. Recovery: Ensure the executable file is in the current directory or is specified in your PATH, and that there is enough memory available. ═══ 19.295. EDC0637 ═══ Unable to open linker response file &1. Recovery: Ensure there is enough disk space available in the TMP directory. ═══ 19.296. EDC0638 ═══ Error in reading from intermediate files. Recovery: Restart the system and compile again. If the problem persists, contact your IBM Service Representative. ═══ 19.297. EDC0639 ═══ Unidentified error in using intermediate files. Recovery: Restart the system and compile again. If the problem persists, contact your IBM Service Representative. ═══ 19.298. EDC0640 ═══ Excess text &1 ignored on &2 option. Extraneous text not used by the option, has been ignored. Recovery: Remove extraneous text. ═══ 19.299. EDC0641 ═══ An object declared as compatible with 16-bit applications is larger than 64K. The /Gt compiler option or #pragma seg16 directive was used with a data object declared as larger than 64K. Recovery: Change the data object so that it is less than 64K in size or remove the /Gt option and/or the #pragma seg16 directive. ═══ 19.300. EDC0642 ═══ #pragma data_seg is ignored for object &1 because #pragma seg16 specified. Recovery: Remove the conflicting #pragma data_seg for the object. ═══ 19.301. EDC0643 ═══ Obsolete C/2 #pragma &1 is no longer supported. A C/2 #pragma directive that is no longer supported was specified. Recovery: Remove the C/2 #pragma directive and use a valid #pragma directive or compiler option in its place. ═══ 19.302. EDC0644 ═══ A _fastcall function cannot be defined in a 32-bit program. A function declared with the _fastcall linkage type, for example, int _Far16 _Fastcall foo(); is defined in this compilation unit. &Theprod. compiles programs to be run in 32-bit mode plus functions which support _cdecl and _pascal calling conventions. Recovery: Do not use _fastcall linkage for the function, or move the function to a different file and compile it with a 16-bit compiler. ═══ 19.303. EDC0645 ═══ The operation between these types is not valid. The identifiers on the left hand side and the right hand side of the operator have types that do not respect the restrictions of the operator. The operation specified in the expression cannot be performed. See Expressions and Operators for the list of operator restrictions. Recovery: Change the operands. ═══ 19.304. EDC0646 ═══ Return type must be compatible with declaration of function &1. The return statement of the function is trying to return a type which is not compatible with the function's declaration. Recovery: Ensure that the value you are returning from the function is correct, or cast the value to the appropriate type before returning it. ═══ 19.305. EDC0647 ═══ Type of the parameter &1 cannot conflict with previous declaration of function &2. The type of this parameter is incompatible with the type of the corresponding parameter in the previous declaration of the function. Recovery: Ensure that the subsequent declaration or function call matches the prototype in both the number and type of parameters. ═══ 19.306. EDC0648 ═══ If the operands are pointers, they must point to compatible types. If one operand of either the relational or the equality operator is a pointer, the other operand must be either a pointer to the same qualified or unqualified type, a NULL pointer, or a pointer to void. Recovery: Change the operands. ═══ 19.307. EDC0649 ═══ User segment &1 has already been declared. The user segment has already been specified as being another type of segment. Data segments and text segments must have distinct names. Recovery: Change the name of the segment. ═══ 19.308. EDC0650 ═══ The maximum number of user defined segments has been exceeded. Recovery: Reduce the number of text and data segments in the program. ═══ 19.309. EDC0651 ═══ A 16-bit function may not have a structure or union as a parameter. Passing a structure or union by value to a 16-bit function is not allowed. Recovery: Change the parameter to a pointer to a structure or union. ═══ 19.310. EDC0652 ═══ The facid was truncated to 3 characters. A facility id can be up to three characters long. The id specified on a #pragma facid() directive was longer than this. The id was truncated to three characters. Recovery: Ensure that the trunctated name is correct. ═══ 19.311. EDC0653 ═══ The value of the flags field on #pragma pit() is bogus. The flags field on a #pragma pit directive contained some bits set which should not be set in a user program. Recovery: Adjust the flags value to make it legal. ═══ 19.312. EDC0654 ═══ The type of the handler function '&1' on the #pragma &2 directive is illegal. The function either has the wrong linkage type, the wrong type for its return value, or an improper parameter list. Recovery: Check the user's guide for the correct function prototype, and fix the declaration as appropriate. ═══ 19.313. EDC0655 ═══ #pragma &1 must appear only once in any C file. Recovery: Remove all but one of the specified #pragma directives. ═══ 19.314. EDC0656 ═══ Only external function name that is defined in the file can be specified in a #pragma &1 directive. Recovery: Ensure that the spelling of the function name is correct, the function name is declared as an external identifier, and the function is defined in the file. ═══ 19.315. EDC0657 ═══ Address of automatic variable taken when DS may not be equal to SS. The address of an auto was taken when the current data segment may may not be the same as the stack segment Recovery: Ensure that this will produce correct results. ═══ 19.316. EDC0658 ═══ Illegal conversion between functions with 16 and 48 bit linkage. A 16 bit function or function pointer cannot be cast to a 48 bit function pointer, and vice-versa. Recovery: Remove the conversion. ═══ 19.317. EDC0659 ═══ The /Gr option must be specified to use _Far32 _Pascal linkage. Recovery: Specify the /Gr compile option, or remove the _Far32 _Pascal linkage. ═══ 19.318. EDC0660 ═══ Cannot use the _Seg16 qualifier with pointers to _Far32 _Pascal functions. Recovery: Remove the _Seg16 type qualifier. ═══ 19.319. EDC0661 ═══ Functions taking a variable number of parameters cannot have _Pascal linkage. Recovery: Change the linkage of the function to be something other than _Pascal. ═══ 19.320. EDC0800 ═══ Parameter &1 is not referenced. The identified variable has been declared in a function parameter list, but never referenced within the function body. Option: /Wpar Recovery: Remove the parameter declaration if it is not needed. ═══ 19.321. EDC0801 ═══ Automatic variable &1 is not referenced. The identified variable has been declared at block scope, but never referenced. Option: /Wuse Recovery: Remove the variable declaration if it is not needed. ═══ 19.322. EDC0802 ═══ Static variable &1 is not referenced. The identified static variable has been declared, but never referenced. Option: /Wuse Recovery: Remove the variable declaration if it is not needed. ═══ 19.323. EDC0803 ═══ External variable &1 is not referenced. The identified variable has been declared either at file scope or extern at block scope, and was never referenced. Option: /Wuse Recovery: Remove the variable declaration if it is not needed. ═══ 19.324. EDC0804 ═══ Function &1 is not referenced. The identified function has been declared, but never referenced. Option: /Wuse Recovery: Remove the function declaration if the function is not needed. ═══ 19.325. EDC0805 ═══ Automatic variable &1 is set but not referenced. The identified variable has been declared and initialized, but never referenced. Variables of type array, struct or union are not checked for this condition. Option: /Wuse Recovery: Remove the variable declaration and initialization if they are not needed. ═══ 19.326. EDC0806 ═══ Static variable &1 is set but not referenced. The identified variable has been declared and initialized, but never referenced. Variables of type array, struct or union are not checked for this condition. Option: /Wuse Recovery: Remove the variable declaration and initialization if they are not needed. ═══ 19.327. EDC0807 ═══ Variable &1 may not have been set before the first reference. The compiler encountered an attempt to access the value of the identified variable before the variable was explicitly initialized. Option: /Wgen Recovery: Ensure the variable is explicitly initialized before its value is accessed. ═══ 19.328. EDC0808 ═══ Variable &1 was not explicitly initialized. If not explicitly initialized, variables with storage class auto or register contain indeterminate values. Option: /Wuni Recovery: Initialize the variable. ═══ 19.329. EDC0809 ═══ &1 redefinition hides earlier one. A typedef was defined at an inner scope with the same name as a previous typedef definition made at an outer scope. The inner scope definition overrides the previous one. Option: /Wgen Recovery: Ensure this is what was intended or use different names for the two typedefs. ═══ 19.330. EDC0810 ═══ External variable &1 is set but not referenced. The identified variable has been declared and initialized, but never referenced. Variables of type array, struct or union are not checked for this condition. Option: /Wext Recovery: Remove the variable declaration and initialization if they are not needed. ═══ 19.331. EDC0811 ═══ Statement has no effect. The statement does not cause any storage to be changed or functions to be called. Option: /Weff Recovery: Change or delete the statement. ═══ 19.332. EDC0812 ═══ Expression has no effect. An expression with no effect has been discovered where expressions with side effects are usually expected. Option: /Weff Recovery: Change or delete the expression. ═══ 19.333. EDC0813 ═══ if-statement is empty. The statement body for an if statement contains no executable code. Option: /Weff Recovery: Change the statement body to contain executable code or delete the if statement. ═══ 19.334. EDC0814 ═══ else-statement is empty. The statement body for an else statement contains no executable code. Option: /Weff Recovery: Change the statement body to contain executable code or delete the else statement. ═══ 19.335. EDC0815 ═══ Loop body is empty. The statement body for a loop statement contains no executable code. Option: /Weff Recovery: Change the statement body to contain executable code or remove the loop statement. ═══ 19.336. EDC0816 ═══ Assignment found in a control expression. The control expression for a switch, if, for, or while statement contains an unparenthesized assignment statement. A common programming problem is the substitution of an assignment statement (i = 3) for what should be a comparison statement (i == 3). Option: /Wcnd Recovery: Verify whether the statement should be an assignment or a comparison. ═══ 19.337. EDC0817 ═══ Type conversion may result in lost precision. The required type conversion may cause lost precision. See -- Reference typcn not found -- for more information on type conversions. for more information on type conversions. Option: /Wtrd Recovery: If precision is important in the operation, eliminate the type conversion. ═══ 19.338. EDC0818 ═══ Pointer type conversion found. Conversion of pointer types may change the pointer values. Option: /Wtrd Recovery: None, if the conversion was intended. Otherwise, declare the pointer to void instead of to another type, and then cast it. ═══ 19.339. EDC0819 ═══ Bitwise operator applied to a signed type. Bitwise operators may change the value of a signed type by shifting the bit used to indicate the sign of the value. Option: /Wpor Recovery: Change the operand to an unsigned type or remove the bitwise operation. ═══ 19.340. EDC0820 ═══ Right shift operator applied to a signed type. A right shift operator may change the value of a signed type by shifting the bit used to indicate the sign of the value. Option: /Wpor Recovery: Change the operand to an unsigned type or remove the shift operation. ═══ 19.341. EDC0821 ═══ Relational expression is always true. The control expression of a switch, if, for, or while statement has a constant value, and the result is always true. This may not be effective code. Option: /Wcnd Recovery: Verify if this result was intended. Change the control expression if necessary. ═══ 19.342. EDC0822 ═══ Relational expression is always false. The control expression of a switch, if, for, or while statement has a constant value, and the result is always false. This may not be effective code. Option: /Wcnd Recovery: Verify if this result was intended. Change the control expression if necessary. ═══ 19.343. EDC0823 ═══ Expression contains division by zero. An expression containing division by zero was found. Option: /Wcns Recovery: Eliminate the division by zero if it was not intended. ═══ 19.344. EDC0824 ═══ Expression contains modulus by zero. An expression containing modulus by zero was found. Option: /Wcns Recovery: Eliminate the modulus by zero if it was not intended. ═══ 19.345. EDC0825 ═══ Code cannot be reached. A statement without a label has been found after an unconditional transfer of control, such as a goto. Option: /Wrea Recovery: If the statement should be executed, make the transfer of control conditional, or label the statement. If not, remove the statement. ═══ 19.346. EDC0826 ═══ Execution fall-through within a switch statement. A case label has been encountered that was not preceded by either a break or return statement. Option: /Wgen Recovery: Precede the case label with a break or return statement. ═══ 19.347. EDC0827 ═══ Nonprototype function declaration encountered. A nonprototype function declaration was found. For example, int addnum(); Function declarations should include the return type of the function and the types of its parameters. Calls to nonprototype functions get no type checking or type conversions on parameters. Option: /Wobs Recovery: Change the nonprototype declarations to prototype declarations such as the following: int addnum(int, int); ═══ 19.348. EDC0828 ═══ The return type of the function main should have type int, not void. If main is declared to return void, the exit code from the program will be indeterminate. Option: /Wobs ═══ 19.349. EDC0829 ═══ Possibly ambiguous operator usage encountered. Expressions consisting of traditional mathematical symbols sometimes have bugs created by misunderstanding of operator precedence. Nonparenthesized expressions containing shift operators, relationals, and bitwise operators may have precedence that is counterintuitive. The identified operator has at least one operand that may have this property. Option: /Word Recovery: Use the appropriate parentheses to eliminate the ambiguity. ═══ 19.350. EDC0830 ═══ Value is not a member of the enumeration. Variables of type enum are not expected to be used in situations other than assignment and comparison, and can only be assigned proper members of their enumeration, either directly, from function return values, or from another variable of the same type. Option: /Wenu Recovery: Ensure operations involving variables of type enum are valid. ═══ 19.351. EDC0831 ═══ Case label is not a member of the enumeration. In a switch statement where the switch control expression is an enum, the case label values must be members of the enumeration. Option: /Wenu Recovery: Ensure the case label is a member of the enumeration. ═══ 19.352. EDC0832 ═══ Unstructured goto statement encountered. The target label of a goto statement should not be located in an inner block such as a loop. Option: /Wgot Recovery: Ensure the target label of the goto statement is not located in an inner block. ═══ 19.353. EDC0833 ═══ Implicit return statement encountered. C allows returns from a function call without specifying a return statement. However, if a function is to return a value, a return statement must be included. Option: /Wret Recovery: Add a return statement to the called function if you want it to return a value. ═══ 19.354. EDC0834 ═══ Missing function return value. The function was declared to return a value, and a return statement with no value has been encountered. If return statement is not included in the function, it will return an indeterminate value to the caller. Option: /Wret Recovery: Add a return value to the return statement. ═══ 19.355. EDC0835 ═══ Structure or union remapping will be performed for this copy operation. A struct or union assignment has been encountered which requires an implicit pack or unpack operation. This form of assignment is often less efficient that those assignments that have identical pack characteristics. Option: /Wgen Recovery: Revise the statements to avoid unnecessary pack and unpack operations. ═══ 19.356. EDC0836 ═══ The same #pragma &1 directive was previously specified for the object &2. The function was already declared using the same #pragma linkage directive. Option: /Wppc Recovery: Remove one of the #pragma linkage directives. ═══ 19.357. EDC0837 ═══ goto statement encountered. A goto statement was found. Option: /Wgot Recovery: No recovery necessary. ═══ 19.358. EDC0838 ═══ Comparison is not valid because the numeric constant is out of range. A comparison between a variable and a constant that is not in the variable's range of possible values has been detected. Option: /Wcns Recovery: Delete the comparison, or use a constant that is in the variable's range of possible values. ═══ 19.359. EDC0839 ═══ Unary minus applied to an unsigned type. An unsigned type cannot have a sign. Option: /Wcns Recovery: Remove the unary minus or change the type to be signed. ═══ 19.360. EDC0841 ═══ File &1 has already #included. The file specified was included by a previous #include directive. Option: /Wppc Recovery: Remove one of the #include directives. ═══ 19.361. EDC0842 ═══ Macro name &1 on #undef not defined. The specified macro name has never been defined or has already been removed by a previous #undef directive. Option: /Wppc Recovery: Define the macro name, or remove the #undef directive. ═══ 19.362. EDC0843 ═══ Macro name &1 on #define is also an identifier. The specified macro definition will override an existing identifier definition. Option: /Wppc Recovery: Rename or remove the macro or the identifier. ═══ 19.363. EDC0844 ═══ Macro name &1 on #define is also a keyword. The specified macro definition will override an existing keyword definition. Option: /Wppc Recovery: Rename the macro or remove the definition. ═══ 19.364. EDC0845 ═══ Identifier &1 assigned default value of 0. The indicated identifier in a #if or #elif expression was assigned the default value of zero. The identifier may have been intended to be expanded as a macro. Option: /Wppc Recovery: Assign the identifier a value if necessary. ═══ 19.365. EDC0846 ═══ Expanding trigraph &1 in string literal. A trigraph has been expanded in a string literal. This may not be the intended behavior. Option: /Wppc Recovery: Ensure this is the intended behavior. If not, use escape sequences to represent characters, for example '\?' for the character '?'. ═══ 19.366. EDC0847 ═══ Expanding trigraph &1 in character literal. A trigraph has been expanded in a character literal. This may not be the intended behavior. Option: /Wppc Recovery: Ensure this is the intended behavior. If not, use escape sequences to represent characters, for example '\?' for the character '?'. ═══ 19.367. EDC0848 ═══ Some program text not scanned due to &1 option. The setting of the margins and/or sequence options has resulted in some program text not being scanned. Option: /Wppc Recovery: Reset the margins and/or sequence options if necessary. ═══ 19.368. EDC0851 ═══ #include found file &1. The message indicates the actual file found for the #include directive. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.369. EDC0852 ═══ #undef undefining macro name &1. This message traces the execution of the #undef directive. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.370. EDC0853 ═══ Macro name &1 on #define has a previous identical definition. The macro has already been identically defined. This may indicate that a file has been #included more than once. Option: /Wppt Recovery: Remove one of the definitions or rename one of the macros. ═══ 19.371. EDC0854 ═══ #line directive changing line to &1 and file to &2. This message traces the execution of the #line directive. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.372. EDC0855 ═══ #&1 condition evaluates to &2. This message traces the evaluation of the test condition of a #if, #ifdef, or #elif directive. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.373. EDC0856 ═══ defined(&1) evaluates to &2. This message traces the evaluation of the defined(&1) construct on a #if or #elif expression. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.374. EDC0857 ═══ Begin skipping tokens. This message traces the execution of conditional compilation directives, for example indicating that code is skipped after a #if with a condition that evaluates to false. Option: /Wppt Recovery: Ensure the appropriate tokens were skipped. ═══ 19.375. EDC0858 ═══ Stop skipping tokens. This message traces the execution of conditional compilation directives, for example, indicating that a #endif marked the end of a block of skipped code. Option: /Wppt Recovery: Ensure the appropriate tokens were skipped. ═══ 19.376. EDC0859 ═══ #&1 nesting level is &2. This message traces the nesting level of conditional compilation directives. Option: /Wppt Recovery: No recovery necessary if the result is what was intended. ═══ 19.377. EDC0860 ═══ String literals concatenated. This message traces the concatenation of two string literals. Option: /Wppt Recovery: Ensure the concatenation is what was intended. ═══ 19.378. EDC0861 ═══ Optional brace encountered. A optional brace was found. Option: /Wini Recovery: No recovery necessary. ═══ 19.379. EDC0862 ═══ Matching optional brace encountered. A matching optional brace was found. Option: /Wini Recovery: No recovery necessary. ═══ 19.380. EDC0863 ═══ Incompletely bracketed initializer encountered, &1 left brace(s) assumed. An initializer for an aggregate type was missing a left brace or braces. The compiler assumes the brace is meant to be there. Option: /Wini Recovery: Ensure this is what was intended. ═══ 19.381. EDC0864 ═══ Incompletely bracketed initializer encountered, &1 right brace(s) assumed. An initializer for an aggregate type was missing a right brace or braces. The compiler assumes the brace is meant to be there. Option: /Wini Recovery: Ensure this is what was intended. ═══ 19.382. EDC0865 ═══ Floating-point constant is out of range. Refer to the <.float.h>. header file for the valid range for floating-point constants. Option: /Wcns Recovery: Ensure the floating-point constant is within the valid range. ═══ 19.383. EDC0866 ═══ Constant arithmetic folding results in an infinity. Floating-point constant arithmetic folding results in an infinity. Option&colon. /Kb Recovery: Ensure this is what was intended. ═══ 19.384. EDC0867 ═══ Constant arithmetic folding results in a NaN. Floating-point constant arithmetic folding results in a NaN. Option: /Wcns Recovery: Ensure this is what was intended. ═══ 19.385. EDC0868 ═══ The incomplete struct or union tag &1 was introduced in a parameter list. The incomplete struct or union tag introduced in the parameter list will not be compatible with subsequent uses of the tag. Option: /Wgen Recovery: Declare the incomplete struct or union tag at file scope before the function declaration. ═══ 19.386. EDC0869 ═══ The incomplete struct or union tag &1 was not completed before going out of scope. An incomplete struct or union tag introduced at block scope was not completed before the end of the scope. Option: /Wgen Recovery: Provide a complete declaration for the struct or union tag. ═══ 19.387. EDC0870 ═══ #line directive changing line to &1. This message traces the execution of the #line directive. Option: /Wppt ═══ 19.388. EDC0871 ═══ Ordinal value on #pragma &1 is out of range. The specified ordinal number should be between 0 and 65535, inclusive. Recovery: Change the value accordingly. ═══ 19.389. EDC0872 ═══ A DLL module name must be specified in #pragma import. Module name is the name of the DLL where the entry point of the import function exists. It must be specified in the parameter list of #pragma import. Recovery: Name the DLL in the parameter list. ═══ 19.390. EDC0873 ═══ Undefined function &1 cannot have a #pragma export or _Export. Recovery: Define the function. ═══ 19.391. EDC0874 ═══ Static function &1 cannot have a #pragma export or _Export. Recovery: Remove the static storage class of the function in order to get it exported. ═══ 19.392. EDC0875 ═══ Definition of function &1 declared as an import encountered. The function was previously declared with the #pragma import directive. Functions declared as import should not be defined in the compilation unit. Recovery: Either remove the #pragma import directive for the function or or remove the definition. ═══ 19.393. EDC0876 ═══ Function &1 was previously specified in #pragma export or _Export. More than one #pragma export directive or _Export was specified for the same object. Recovery: Remove the extra #pragma export directives or _Export. ═══ 19.394. EDC0877 ═══ Function &1 was previously defined and should not be redeclared as an import encountered. Recovery: Rename the function. ═══ 19.395. EDC0884 ═══ Unable to open precompiled output file &1. Reason: &2. Recovery: Ensure that the compiler has write access for the precompiled output file. ═══ 19.396. EDC0885 ═══ Unable to write precompiled output file &1. Reason: &2. Recovery: Ensure that the compiler has write access for the precompiled output file and that there is enough disk space for writing the file. ═══ 19.397. EDC0886 ═══ Unable to open precompiled input file &1. Reason: &2. Recovery: Ensure that the compiler has read access for the precompiled output file. ═══ 19.398. EDC0887 ═══ Precompiled data in the file &1 does not have the correct format. The original header file will be used. Recovery: Remove the corrupt precompiled version of the header file and re-generate it with the /Fi+ option. ═══ 19.399. EDC0888 ═══ Precompiled data in the file &1 cannot be used because it was produced by a later version of the compiler. The original header will be used. Recovery: Erase the precompiled version of the header file and re-generate it with the current version of the compiler. ═══ 19.400. EDC0889 ═══ Precompiled header file &1 found but not used because it is not up to date. Recovery: Use /Fi+ option to generate an up to date version of the precompiled header file. ═══ 19.401. EDC0890 ═══ Using precompiled header file &1. ═══ 19.402. EDC0891 ═══ Generated precompiled header file &1. ═══ 19.403. EDC0900 ═══ Unable to open &1. Recovery: Ensure file exists. ═══ 19.404. EDC0902 ═══ Unable to write to &1. Recovery: Ensure that the disk drive is not in an error mode and that there is enough disk space left. ═══ 19.405. EDC3000 ═══ Version 1.120. warning : The message file DDE45.MSG is out of date. The message file found is not the correct version for the compiler being invoked. The compiler requires a specific version of the message file DDE45.MSG in the help directory to display messages. Recovery: Check the DPATH environment variable and/or update the message file. If you have copied over the files in the the \ibmcpp\help or the \ibmcpp\bin directories, then the message files may be out of date. ═══ 19.406. EDC3001 ═══ "private" assumed for base class "&1". No access specifier has been provided for a base class. A base class can be declared with the access specifier "public" or "private". The C++ language specification requires that "private" becomes the default when no access specifier is present. It is good coding practice to explicitly provide the access specifier for the base class. Recovery: Provide an access specifier or accept the default. ═══ 19.407. EDC3002 ═══ "&1" is not used in function "&2". The specified symbol has been declared within a function but it has not been set or used. This is only an informational message since it is permitted to have declared yet unused symbols, but it is probably undesirable. Recovery: Ignore the message, use the symbol, or remove the symbol. ═══ 19.408. EDC3003 ═══ Ambiguous conversion between "&1" and "&2". The compiler was not able to find a single type common to the two specified types. Recovery: Check the types. ═══ 19.409. EDC3004 ═══ "&1" statement is not allowed in this scope. The specified statement was found outside the valid scope for such a statement. This typically means that it is outside any function. Recovery: Place the statement in the correct scope or remove it. ═══ 19.410. EDC3005 ═══ Duplicate "default" statement in switch. Only one "default" label is allowed in a "switch" statement. This "default" label is not the first in the switch. Recovery: If you have nested switch statements, check that the braces match correctly. If not, remove one of the "default" labels. ═══ 19.411. EDC3006 ═══ Duplicate definition of label "&1". The specified label has already been defined in the current function. A label can only be declared once within a function. Recovery: Remove or rename one of the label definitions. ═══ 19.412. EDC3007 ═══ The "#line" macro directive may cause information for the browser to be corrupted. The compiler generates information for the class browser. Using the "#line" preprocessor directive may cause that information to be corrupted. Recovery: Remove the "#line" macro directive or note the possible corruption. ═══ 19.413. EDC3008 ═══ Source file &1 cannot be opened. The compiler could not open the specified source file. Recovery: Ensure the source file name is correct. Ensure that the correct file is being read and has not been corrupted. If the file is located on a LAN drive, ensure the LAN is working properly. Also, the file may be locked by another process or access may be denied because of insufficient permission. ═══ 19.414. EDC3009 ═══ An error occurred while reading file "&1". The compiler detected an error while reading from the specified file. Recovery: Ensure the correct file is being read. If the file resides on a LAN drive, ensure that the LAN is working properly. ═══ 19.415. EDC3010 ═══ Source file name is missing. The name of the source file to be compiled was missing from the compiler invocation. Ensure the compile options are specified correctly; the compiler may misinterpret the command line if the options are specified incorrectly. Recovery: Ensure that you specify the source file name. ═══ 19.416. EDC3011 ═══ "&1" is unmatched at end of file. The end of the source file was reached and the comment or block was not closed. It is also possible that there was a typographical error made earlier in the source file Recovery: Check the source file for typographical errors. End the comment or block before the end of the file. ═══ 19.417. EDC3012 ═══ A return value is not allowed for this function. A "return" statement with a return expression is not allowed when the enclosing function has a return type of "void". Recovery: Either specify "return" without a value or expression, or remove the "return" statement from the function. ═══ 19.418. EDC3013 ═══ "&1" is undefined. The specified identifier is being used but has not yet been defined. Recovery: Define the identifier before using it. Check its spelling. If the identifier has been defined in a header file, check that any required macros have been defined. ═══ 19.419. EDC3014 ═══ Wrong number of arguments for macro "&1". The specified macro was defined with a different number of arguments than are used in this macro call. Recovery: Ensure that the macro call corresponds to the macro definition. Check the number and levels of corresponding braces in the macro. ═══ 19.420. EDC3015 ═══ The compiler could not open the output file "&1". Recovery: Ensure the output file name is correct. Also, ensure that the location of the output file has sufficient storage available. If using a LAN drive, ensure that the LAN is working properly and you have permission to write to the disk. ═══ 19.421. EDC3016 ═══ &1 member "&2" cannot be accessed. The specified member is private, protected or is a member of a private base class and cannot be accessed from the current scope. Recovery: Check the access specification rules for the member function and change the access specifier if necessary. If the member function belongs to a base class, check the access specifier of the base class where the current class is defined. ═══ 19.422. EDC3017 ═══ Return value of type "&1" is expected. No return value is being returned from the current function but the function is expecting a non-void return value. The function was declared with a return type but the compiler did not detect a return statement. A return statement without an expression, or no return statement at all, can only be used in functions with the return value type "void". Recovery: Return a value to the function or change the return type to void. ═══ 19.423. EDC3018 ═══ "&1" cannot be made a &2 member. An attempt is being made to give private access to a base class member or to give access that is different from the access it was declared with. A derived class can only change the access of a base class member function to public or protected. Recovery: Remove the invalid access statement or change the access specifier in the base class. ═══ 19.424. EDC3019 ═══ Case expression is not an integral constant expression. The expression in a "case" statement must be an integral constant expression followed by a colon. Recovery: Use an integral constant expression. A constant expression has a value that can be determined during compilation and does not change during execution. ═══ 19.425. EDC3020 ═══ "asm" keyword declaration is not supported. The compiler does not support "asm" declarations. The declaration is ignored. Recovery: Remove the "asm" keyword. ═══ 19.426. EDC3021 ═══ Expected "end of line" and found "&1" in preprocessor directive. The compiler detected a preprocessor directive at the beginning of this line and then detected an error in the rest of the directive. The rest of the line in the preprocessor directive is ignored. Recovery: Remove the unexpected token so that only the preprocessor directive appears on the line. ═══ 19.427. EDC3022 ═══ "&1" was previously declared as "&2". The declaration conflicts with a previous declaration of the same name. Recovery: Change one of the names or eliminate one of the declarations. ═══ 19.428. EDC3023 ═══ "&1" has already been defined. An attempt is being made to define a name that has already been defined. Recovery: Change one of the names or remove one of the definitions. Check the spelling or the scope of the two variables. ═══ 19.429. EDC3024 ═══ Declaration of "&1" must be a function definition. A declaration of a member function outside its member list must be a function definition. A method of a class that has already been declared inside a class declaration cannot be redeclared outside the class. Recovery: Either remove the member function declaration outside the member list or change it to a definition. ═══ 19.430. EDC3025 ═══ "&1" conflicts with "&2". Both the specified attributes are part of a declaration but they cannot both be specified in the same declaration. Recovery: Remove one of the specified attributes. ═══ 19.431. EDC3026 ═══ Keyword "&1" is not allowed. The specified keyword is not allowed in this context. Recovery: Remove the keyword. ═══ 19.432. EDC3027 ═══ Preprocessor directive "#&1" is not recognized. The compiler identified a # character at the start of a line and could not recognize the preprocessor directive following it. Recovery: Check the spelling of the preprocessor directive. ═══ 19.433. EDC3028 ═══ The syntax of the file name in the "#include" directive is not valid. The compiler detected an #include preprocessor directive but could not parse the file name. The file name must be surrounded by a " or < after the #include directive. Recovery: Correct the syntax of the file name. ═══ 19.434. EDC3029 ═══ Expected integer line number and found "&1". The operand of the "#line" directive must be an integer line number. Recovery: Ensure that the "#line" directive contains an integer line number operand. ═══ 19.435. EDC3030 ═══ The macro "&1" has already been defined. An active definition already exists for the macro name being defined. The second definition will be ignored. Recovery: Remove or rename one of the macro definitions. ═══ 19.436. EDC3032 ═══ Unexpected preprocessor directive "#&1". An "#else", "#elif" or "#endif" preprocessor directive was found out of context. Recovery: Remove or move the preprocessor directive. ═══ 19.437. EDC3033 ═══ The for-init-statement must be a declaration or expression. The initializer statement within a "for" statement must be a declaration or expression statement. Recovery: Change the for-init-statement to a declaration or an expression. ═══ 19.438. EDC3034 ═══ "&1" has a function body but is not a function. The name is not declared as a function; there may be parentheses missing from the declaration. Recovery: Correct the declaration. ═══ 19.439. EDC3035 ═══ The array bound in "&1" is missing. An array must be defined with at least one element. Use a pointer is you want to dynamically allocate memory for the array. Recovery: Add an array bound. ═══ 19.440. EDC3036 ═══ The bit-field length must be an integral constant expression. The bit-field width, which is the value to the right of the colon, must be an integer. Recovery: Change the bit-field length to an integral constant expression. A constant expression has a value that can be determined during compilation and does not change during execution. ═══ 19.441. EDC3037 ═══ "&1" is not a base class of "&2". A derived class can only access elements of its base class or base classes. Recovery: Ensure the class names are correct and the classes are derived properly. ═══ 19.442. EDC3038 ═══ The array bound must be a positive integral constant expression. The compiler detected an array declaration that did not have a constant that is greater than 0 for the array bounds. Use pointers if you want to dynamically allocate storage for arrays. Recovery: Change the array bound to an integral constant expression or change it to a pointer. A constant expression has a value that can be determined during compilation and does not change during execution. ═══ 19.443. EDC3039 ═══ "&1" has the same name as its containing class. The compiler has detected conflicting names for objects within a class declaration. Note that nested class declarations must have different names. Recovery: Change the name of the conflicting class. ═══ 19.444. EDC3040 ═══ A destructor can only be used in a function declaration or in a function call. The compiler has detected an incorrect destructor call. Recovery: Check the call to the destructor to ensure no braces are missing. If the braces are correct, remove the destructor call. ═══ 19.445. EDC3041 ═══ An initializer is not allowed for "&1". Recovery: Remove the initializer. ═══ 19.446. EDC3042 ═══ Function "&1" is nested within another function. Functions must not be nested in C++. Recovery: Ensure that a "}" is not missing before the start of the function. ═══ 19.447. EDC3043 ═══ The string must be terminated before the end of the line. The compiler detected a string that was not terminated before an end-of-line character was found. Recovery: End the string or use "\" to continue the string on the next line. The "\" must be the last character on the line. ═══ 19.448. EDC3044 ═══ extern "&1" is not a recognized linkage; extern "C" is assumed. The linkage string in a linkage declaration is not one of the linkages supported by this compiler. Recovery: Change the linkage string to a valid value or make it "C". ═══ 19.449. EDC3045 ═══ Syntax error in directive - expected "&1" and found "&2". A syntax error was found during preprocessing. The message identifies what the compiler expected and what it actually found. Recovery: Correct the syntax. ═══ 19.450. EDC3046 ═══ "&1" is not a variable. The compiler detected a non-variable type where one was required. Recovery: Change the usage of the name. ═══ 19.451. EDC3047 ═══ An expression of type "&1" cannot be followed by the function call operator (). The compiler detected an expression followed by the function call operator. The expression must be of type function, pointer to function or reference to function. Recovery: Change the type of expression or remove the function call operator. ═══ 19.452. EDC3048 ═══ The "this" keyword is only valid in class scope. An attempt to use the C++ keyword "this" was detected outside class scope. The keyword "this" cannot be used outside a class member function body. Recovery: Remove or move the "this" keyword. ═══ 19.453. EDC3049 ═══ The option "&1" is not supported. The command line contained an option that is not supported. Note that some option parameters must not have spaces between the option and the parameter. Recovery: Remove the option. Check the syntax of the options. ═══ 19.454. EDC3050 ═══ A destructor cannot have arguments. Recovery: Remove the arguments from the destructor. ═══ 19.455. EDC3051 ═══ A declaration has been made without a type specification. The compiler detected a typedef specification that did not have a type associated with it. Recovery: Add a type specification to the declaration. ═══ 19.456. EDC3052 ═══ Return type cannot be specified for "&1". The compiler detected a return type where one is not permitted. For example, putting a return type on a constructor is not permitted. Recovery: Remove the return type specification for the function. ═══ 19.457. EDC3053 ═══ Class qualification for "&1" is not allowed. Explicit class qualification is not allowed in this context. Recovery: Remove the class qualification. ═══ 19.458. EDC3054 ═══ The "&1" operator is not allowed between "&2" and "&3". The compiler detected an illegal operator between two operands. For user-defined types, the operator needs to be overloaded to accept the user-defined types. Recovery: Change the operator or change the operands. ═══ 19.459. EDC3055 ═══ "&1" cannot be converted to "&2". The type conversion cannot be performed. This can occur in an initialization, assignment, or expression statement. Recovery: Change one of the types or overload the operator. ═══ 19.460. EDC3056 ═══ Operand for "&1" must be a pointer or an array. Recovery: Change the operand to either a pointer or an array. ═══ 19.461. EDC3057 ═══ Syntax error - "&1" is not a class name. A class name must be specified in this context. Recovery: Specify a class name. Check the spelling. ═══ 19.462. EDC3058 ═══ Operand of "&1" operator must be an lvalue. The compiler detected an operand that is not an lvalue. For example, the left hand side of an assignment statement must be an lvalue. An lvalue is an expression that represents an object. Recovery: Change the operand to an lvalue. ═══ 19.463. EDC3059 ═══ const expression cannot be modified. A const object may be initialized but its value cannot change afterwards. Recovery: Eliminate the const type qualifier from the expression or remove it from increment/decrement operators. ═══ 19.464. EDC3060 ═══ An expression of type "&1" is not allowed on the left side of "&2". The compiler detected a mismatch between the operands of an operator. Recovery: Change the type or operator. ═══ 19.465. EDC3061 ═══ "&1" is neither a base class nor a non-static member of class "&2". The compiler has detected an element of the initializer list that is not an element of the member list. Only immediate base classes and members not inherited from a base class may be initialized using the constructor initializer list. Recovery: Change the constructor initializer list. ═══ 19.466. EDC3062 ═══ Constructor init list is not allowed for non-constructor function. Recovery: Remove the constructor initializer list. ═══ 19.467. EDC3063 ═══ Variable "&1" is not allowed in an argument initializer. The compiler has detected an illegal variable in an argument initializer. Recovery: Remove the variable from the argument initializer. ═══ 19.468. EDC3064 ═══ There are too many initializers in the initializer list. The compiler detected more initializers than were present in the declaration. Recovery: Remove one or more initializers from the initializer list. ═══ 19.469. EDC3065 ═══ An initializer is not allowed for an array allocated by "new". Recovery: Remove the initializer or the "new" allocation. ═══ 19.470. EDC3066 ═══ The bit-field length must not be more than &1. The bit-field length must not exceed the maximum bit size of the bit-field type. Recovery: Reduce the bit-field length. ═══ 19.471. EDC3067 ═══ The type of "&1" cannot be "&2". The compiler detected a conflict in a type declaration. Recovery: Change the type. ═══ 19.472. EDC3068 ═══ Function overloading conflict between "&1" and "&2". The compiler detected function argument types that it could not resolve to be unique. Recovery: Check the declarations of the functions. ═══ 19.473. EDC3069 ═══ Declarations of the same &1 must not specify default initializers for the same argument. The compiler has detected an overloaded function or template that was declared with the same argument having default initializers. Recovery: Ensure that you wanted to declare the same function or template. If that is the case, remove one of the default initializers. Otherwise, remove one of the declarations or overload the function. ═══ 19.474. EDC3070 ═══ Call does not match any argument list for "&1". No variant of the overloaded function matches the argument list on the call any better than all other variants. The argument mismatch could be by type or number of arguments. Recovery: Change the argument list on the call to the overloaded function or change the argument list on one of the overloaded function variants so that a match is found. ═══ 19.475. EDC3071 ═══ Call to "&1" matches more than one function. More than one variant of the overloaded function matches equally well with the argument list specified on the call. Recovery: Change the argument list on the call to the overloaded function or change the argument list on one of the overloaded function variants so that one match is found. ═══ 19.476. EDC3072 ═══ Linkage for "&1" cannot be redefined. The specified name has already been declared with a different linkage than the current declaration. Recovery: Remove the redefinition or change one of the names. ═══ 19.477. EDC3073 ═══ The "operator" declaration must declare a function. The keyword "operator" can only be used to declare an operator function. Recovery: Check the declaration of the operator and make sure the function declarator () appears after it. Use the "operator" keyword to declare an operator function or remove it. ═══ 19.478. EDC3074 ═══ Operand for "&1" is of type "&2" which is not a member pointer type. The specified operator must have an operand which is of type pointer to member. Recovery: Change the operand to type pointer to member. ═══ 19.479. EDC3075 ═══ "&1" is not allowed as a function return type. A function cannot be declared with a function or an array as its return type. Recovery: Declare the function as returning a pointer to the function or the array element type. ═══ 19.480. EDC3076 ═══ "&1" is not allowed as an array element type. The C++ language does not allow the declaration of an array of functions, references or void. Recovery: Remove the declaration or change the declaration so that it is an array of pointer to functions, references, or void. ═══ 19.481. EDC3077 ═══ const variable "&1" does not have an initializer. A const variable can only be assigned a value is with an initializer. This variable has no initializer, so it can never be given a value. Recovery: Initialize the variable or remove the "const" keyword. ═══ 19.482. EDC3078 ═══ Non-static member "&1" must be associated with an object or a pointer to an object. The compiler detected a non-static member that makes reference to a specific object that has not been instantiated. Only static members can be referenced without associating them with an instance of the containing class. Recovery: Check the spelling and the class definition. Change the name of the class or function, or define the function as static in that class. ═══ 19.483. EDC3079 ═══ "&1" is not a member of "&2". The name has been explicitly given the specified class as a scope qualifier but the class does not contain a member of that name. Recovery: Check the spelling of the scope qualifier. ═══ 19.484. EDC3080 ═══ Wrong number of arguments for "&1". Either a function or an explicit cast has been specified with the wrong number of arguments. Recovery: Use the correct number of arguments. Ensure that overloaded functions have the correct number and type of arguments. ═══ 19.485. EDC3081 ═══ "&1" must be a class member. Conversion functions and certain operator functions must be class members. They cannot be defined globally. Recovery: Remove the global definition or make "&1" a class member. ═══ 19.486. EDC3082 ═══ An argument type of "&1" is not allowed for "&2". This is a declaration of a function that has restrictions on what types its arguments can have. The specified type is not allowed for this argument. Recovery: Change the argument type. ═══ 19.487. EDC3083 ═══ "&2" cannot have a return type of "&1". The specified operator function has the wrong return type. Recovery: Change the return type. ═══ 19.488. EDC3084 ═══ One of the operands for the array operator must be of pointer type and the other operand must be of integral type. This error may result from the improper use of the array operator. Recovery: Change the operands of the array operator. ═══ 19.489. EDC3085 ═══ Wrong number of arguments specified in the function call. The number of arguments in the function call does not match the number of arguments in the function declaration. Recovery: Specify the correct number of arguments. ═══ 19.490. EDC3086 ═══ &1 This message has been generated by the "#error" preprocessor directive, which is a user-defined error message placed in the source code. ═══ 19.491. EDC3087 ═══ "&1" operator is not allowed for type "&2". The specified operator cannot be used with operands of this type. Recovery: Change either the operator or the operands. ═══ 19.492. EDC3088 ═══ Insufficient memory. The compiler ran out of memory during compilation. Recovery: End unnecessary processes and recompile. ═══ 19.493. EDC3089 ═══ More than one function "&1" has non-C++ linkage. If a function is overloaded, at most one of its variants can have non-C++ linkage. Recovery: Remove one of the non-C++ linkages or do not overload the function. ═══ 19.494. EDC3090 ═══ Syntax error - expected "&1" and found "&2". A syntax error was found while parsing the program. The message identifies what the compiler expected and what it actually found. Often the source of the error is an unmatched parenthesis or a missing semicolon. Recovery: Correct the syntax. ═══ 19.495. EDC3091 ═══ "&1" is not allowed for &2. The attribute or name cannot be specified in the given context. The compiler detected incompatible names that conflicts with the language definition. Recovery: Remove the attribute or name. ═══ 19.496. EDC3092 ═══ "&1" conflicts with previous "&2" declaration. The declaration conflicts with a previous declaration of the same symbol. Recovery: Remove one of the declarations. ═══ 19.497. EDC3093 ═══ Initializer is too long. The string initializer for a character or wide-character array has more characters than the array. Note that the trailing null character is treated as part of the initializer. Recovery: Increase the array or reduce the initializer. ═══ 19.498. EDC3094 ═══ The "operator->" function must return either a class type, a reference to a class type or a pointer to class type and the class type must itself have an "operator->" function. Recovery: Change the return value of the "operator" function. ═══ 19.499. EDC3095 ═══ Unused "&1" definition. This is an unnamed class or struct definition that has no object associated with it. The definition can never be referenced. A class can be unnamed, but it cannot be passed as an argument or returned as a value. An unnamed class cannot have any constructors or destructors. Recovery: Create an object for the class or struct, or remove the definition. ═══ 19.500. EDC3096 ═══ Internal compiler error at line &1 in module "&2": &3. The compiler detected an error that it is not able to recover from. The error was found within the compiler itself. Recovery: Note the line and module references in this message. Contact your IBM Representative. ═══ 19.501. EDC3097 ═══ Reference to member "&1" of undefined class "&2". The member has been explicitly given the specified class as a scope qualifier but the class (and hence the member) has not been defined. Recovery: Check for a missing #include file. Define the class and member. ═══ 19.502. EDC3098 ═══ Pointer conversion may be wrong if the classes are related in a multiple inheritance hierarchy. The relationship between the classes in a pointer conversion is not known. If the target class is later defined as a base class of the source class in a multiple inheritance, this conversion will be wrong if the value of the pointer should have been modified by the conversion. Recovery: Change the ambiguous reference in the conversion. ═══ 19.503. EDC3099 ═══ "&1" is used but not set in function "&2". The specified symbol is being used but has not been assigned a valid value. Its value will be undefined. Recovery: Define or initialize the symbol before using it. ═══ 19.504. EDC3100 ═══ "&1" is set but not used in function "&2". The specified symbol has been given a value but the symbol has not been used. Recovery: Use the symbol or remove it. ═══ 19.505. EDC3101 ═══ "&1" may be used before being set. The specified symbol is being used before it has been assigned a value. The value of the symbol is undefined. Recovery: Define or initialize the symbol before using it. ═══ 19.506. EDC3102 ═══ The reference variable "&1" is uninitialized. Reference variables must be initialized. Recovery: Initialize the reference variable or remove it. ═══ 19.507. EDC3103 ═══ "&1" must already be declared. The specified class or enum name must have been declared before this use of the name. Recovery: Rename or remove the declaration. ═══ 19.508. EDC3104 ═══ Unrecognized source character "&1", code point &2. The specified character is not a valid character in a C++ program. The code point represents the ASCII value of the character displayed in hexadecimal format. Recovery: Remove the character. ═══ 19.509. EDC3105 ═══ A local class cannot have a non-inline member function "&1". A class declared within a function must have all of its member functions defined inline, since the class will go out of scope before non-inline functions can be defined. Recovery: Define the functions inline, or move the class definition out of the scope of the function. ═══ 19.510. EDC3106 ═══ The size of "&1" is unknown. The operation cannot be performed because the size of the specified type is not known. Recovery: Specify the size of the type. ═══ 19.511. EDC3107 ═══ Assignment in logical expression. The logical expression contains an assignment (=). An equality equality comparison (==) may have been intended. Recovery: Change the operator or the expression. ═══ 19.512. EDC3108 ═══ Conversion from "&1" to "&2" may cause truncation. The specified conversion from a wider to a narrower type may cause the loss of significant data. Recovery: Remove the conversion from a wider to a narrower type. ═══ 19.513. EDC3109 ═══ "goto &1" bypasses initialization of "&2". Jumping past a declaration with an explicit or implicit initializer is not valid unless the declaration is in an inner block or unless the jump is from a point where the variable has already been initialized. Recovery: Enclose the initialization in a block statement. ═══ 19.514. EDC3110 ═══ References to "&1" may be ambiguous. The name is declared in base classes "&2" and "&3". Recovery: Change one of the names, or always fully qualify the name. ═══ 19.515. EDC3111 ═══ Ambiguous reference to "&1", declared in base classes "&2" and "&3". The name is a member of more than one base class and the compiler cannot determine which one to choose. Recovery: Change one of the names, or always fully qualify the name. ═══ 19.516. EDC3112 ═══ Conversion from "&1" to "&2" is ambiguous. There is more than one way to perform the specified conversion. This may be caused by an overloaded function. Recovery: Change or remove the conversion. ═══ 19.517. EDC3113 ═══ "&1" is only valid for non-static member functions. const and volatile are only significant for non-static member functions, since they are applied to the "this" pointer. Recovery: Remove const and volatile from all static members. ═══ 19.518. EDC3114 ═══ Duplicate case value. Case values must be unique within each "switch" statement. Recovery: Change or remove one of the duplicate case values. Check the braces if you have nested case statements. ═══ 19.519. EDC3115 ═══ Character literal is null. An empty character literal has been specified. A string literal may have been intended. Recovery: Remove the character literal, change it to a string literal, or give it a value. ═══ 19.520. EDC3116 ═══ "&1" is given wider scope for compatibility reasons. A type defined in class scope has been given the scope of the enclosing function or file because of a compiler option. Recovery: Ensure this is the desired response. ═══ 19.521. EDC3117 ═══ "&1" has more than one base class "&2". A derived class has inherited the same base class in more than one path and the compiler cannot determine which one to choose. Recovery: Remove one of the inheritances. ═══ 19.522. EDC3118 ═══ "&1" is a &2 base class of "&3". An attempt is being made to convert a pointer to a derived class into a pointer to a private or protected base class. Recovery: Remove the pointer conversion. ═══ 19.523. EDC3119 ═══ The statement is unreachable. Flow of control in the program is never allows the statement to be be reached. Recovery: Ensure that the statement is accessible to the flow of control, or remove the statement. ═══ 19.524. EDC3120 ═══ &1 "&2" is not allowed in a union. Unions must not be declared with base classes, virtual functions, static data members, members with constructors, members with destructors or members with class copying assignment operators. Recovery: Remove any such members from the union declaration. ═══ 19.525. EDC3121 ═══ union "&1" cannot be used as a base class. Unions cannot be used as base classes for other class declarations. Recovery: Remove the union as a base class for other class declarations. ═══ 19.526. EDC3122 ═══ Local variable "&1" is inaccessible from "&2". An automatic variable within a function is not accessible from local classes declared within the function. Recovery: Remove the reference to the local variable. ═══ 19.527. EDC3123 ═══ Value of enumerator "&1" is too large. The value of an enumerator must be a constant expression that is promotable to a signed int value. Recovery: Reduce the value of the enumerator. ═══ 19.528. EDC3124 ═══ Missing path name in include directive. Recovery: Add path name to the #include directive. ═══ 19.529. EDC3125 ═══ Missing "#define" or "#undef". Recovery: Add "#define" or "#undef". ═══ 19.530. EDC3126 ═══ Argument "&1" is not used in function "&2". The specified symbol has been declared as an argument to a function but has not been set or used. Recovery: Use the symbol or remove it. ═══ 19.531. EDC3127 ═══ Global symbol "&1" is not used. The specified symbol has been declared as a global symbol but has not been set or used. Recovery: Remove the symbol or remove it. ═══ 19.532. EDC3128 ═══ "main" returns an uninitialized value to the invocation environment. No return value is being returned from main() but main() has a non-void return value. Recovery: Return a value from "main" or declare it as "void". ═══ 19.533. EDC3129 ═══ Default initializers are not allowed in local friend functions. Recovery: Remove the default initializers from the local friend function. ═══ 19.534. EDC3130 ═══ A constant is being used as a conditional expression. The condition to an if, for, or switch is constant. Recovery: Remove the constant from the conditional expression or ignore this message. ═══ 19.535. EDC3131 ═══ The argument to a not (!) operator is constant. The compiler has detected a constant after the ! operator which may be a coding error. Recovery: Remove the constant or ignore this message. ═══ 19.536. EDC3132 ═══ There is more than one character in a character constant. Using more than one character in a character constant (for example, 'ab') may not be portable across machines. Recovery: Remove the extra character(s) or change the character constant to a string constant. ═══ 19.537. EDC3133 ═══ Possible pointer alignment problem with the "&1" operator. A pointer that points to an object of loose alignment is being assigned, cast, returned or passed as a parameter to a pointer of stricter alignment. Recovery: Remove the pointer reference or change the alignment. ═══ 19.538. EDC3134 ═══ A constant expression is being cast to a pointer. A constant value is being cast to a pointer. This is nonportable. Recovery: Remove the constant expression from the cast expression. ═══ 19.539. EDC3135 ═══ Precision was lost in assignment to a (possibly sign-extended) field. Recovery: Change the assignment expression. ═══ 19.540. EDC3136 ═══ Precision was lost in field assignment. Recovery: Change the assignment expression. ═══ 19.541. EDC3137 ═══ Enumeration type clash with the "&1" operator. Operands from two different enumerations are used in an operation. Recovery: Ensure both operands are from the same enumeration. ═══ 19.542. EDC3138 ═══ Comparison of an unsigned value with a negative constant. An unsigned value is being compared to a negative number. Recovery: Remove the comparison or change the type. ═══ 19.543. EDC3139 ═══ Unsigned comparision is always true or always false. The comparison is either unsigned >= 0 which is always true or unsigned < 0 which is always false. Recovery: Remove or change the comparison. ═══ 19.544. EDC3140 ═══ Comparison is equivalent to "unsigned value &1 0". The comparison is either "unsigned > 0" or "unsigned <= 0", and could be written as "unsigned != 0" or "unsigned == 0". Recovery: Change the comparison. ═══ 19.545. EDC3141 ═══ Argument &1 for "&2" must be of type "&3". For this type of function, the specified argument must be of a particular type but the specified type is of a particular type that is different from the type specified. Recovery: Ensure that the argument is of the correct type. ═══ 19.546. EDC3142 ═══ The operand for the "#line" directive must be an integer in the range 1 to 32767. The operand of the "#line" directive must be an integer in the specified range. Recovery: Ensure that the operand is in the specified range. ═══ 19.547. EDC3143 ═══ Definition of "&1" is not allowed. The specified type is being defined in a place where it is not valid to do so; that is, in a type cast or a conversion function declaration. Recovery: Move the definition to a new location, or remove it. ═══ 19.548. EDC3144 ═══ Reference to "&1" is not allowed. The name has a special meaning in a C++ program and cannot be referenced in this way. Recovery: Remove the reference. ═══ 19.549. EDC3145 ═══ An octal constant is too large for character representation. Only the rightmost eight bits are used for the character. Recovery: Make the octal constant smaller. ═══ 19.550. EDC3146 ═══ A hexadecimal constant is larger than two digits. Only the rightmost two digits are used for the character. Recovery: Make the hexadecimal constant smaller. ═══ 19.551. EDC3147 ═══ A character constant is larger than the size of an "int". Only the rightmost &1 characters are used. Recovery: Make the character constant smaller. ═══ 19.552. EDC3148 ═══ Linkage specification must be at file scope. A linkage specification may only be defined at file scope, that is, outside all functions and classes. Recovery: Move the linkage specification or remove it. ═══ 19.553. EDC3149 ═══ Default initializers cannot be followed by uninitialized arguments. If default initializers are specified in an argument list, there must be default initializers for all later arguments. Recovery: Remove the default initializers, or provide them for all later arguments, or move the arguments to the end of the list. ═══ 19.554. EDC3150 ═══ The address of "&1" cannot be taken. The address of a constructor or destructor cannot be taken. Recovery: Remove the address operator (&) from the expression or remove the expression. ═══ 19.555. EDC3151 ═══ &1 compiler temporary of type "&2" has been generated. The compiler has generated a temporary variable whose lifetime may be limited. Recovery: Ensure that the code does not depend on the value of a temporary which will be automatically destroyed when it goes out of scope. ═══ 19.556. EDC3152 ═══ An error was detectect while writing to file "&1". Recovery: Ensure the file name is correct and that the disk is ready to be written to. ═══ 19.557. EDC3153 ═══ Duplicate qualifier "&1" ignored. The keyword has been specified more than once. Extra occurrences are ignored. Recovery: Remove one of the duplicate qualifiers. ═══ 19.558. EDC3154 ═══ "&1" operator cannot be overloaded. The specified operator cannot be overloaded using an operator function. The following operators cannot be overloaded: Recovery: Remove the overloading declaration or definition. ═══ 19.559. EDC3155 ═══ At least one argument of "&1" must be of class type. The operator function must be a member of a class, so it must have at least one argument which is of class type. Recovery: Add an argument of class type. ═══ 19.560. EDC3156 ═══ Call matches builtin operator. Recovery: Ensure this is the desired match. ═══ 19.561. EDC3157 ═══ The divisor for the modulus or division operator cannot be zero. Recovery: Change the expression used in the divisor. ═══ 19.562. EDC3158 ═══ The address of the bit-field "&1" cannot be taken. An attempt is being made to take the address of a bit-field or to use the bit-field to initialize a reference variable or argument. Recovery: Remove the expression that either takes the address of the bit-field or uses the bit-field to initialize a reference variable or argument. ═══ 19.563. EDC3159 ═══ "&1" must not have default initializers. Default initializers are not allowed within the declaration of an operator function or a template function. Recovery: Remove the default initializers. ═══ 19.564. EDC3160 ═══ The &1 "&2" needs a constructor initializer. Base classes, and class members with constructors and no default constructor, need to have an initializer specified in the constructor initializer list. Recovery: Specify a constructor initializer. ═══ 19.565. EDC3161 ═══ Line is too long for proper generation of test coverage information. No statement may start to the right of the 2**16 column (65536) when test coverage information is to be generated. Recovery: Shorten the line. ═══ 19.566. EDC3162 ═══ There are too many statements for proper generation of test coverage information. There can be no more than 2**16 (65536) statements (not source lines) in a module when test coverage information is to be generated. Recovery: Reduce the number of statements. ═══ 19.567. EDC3163 ═══ Template class "&1" has the wrong number of arguments. A template class instantiation has a different number of template arguments than the template declaration. Recovery: Ensure that the template class has the same number of declarations as the template declaration. ═══ 19.568. EDC3164 ═══ Non-&1 member function "&2" cannot be called for a &1 object. The member function is being called for a const or volatile object but it has not been declared with the corresponding const or volatile attribute. Recovery: Ensure that either both the function call and function declarations have the "const" or "volatile" keyword, or neither have. ═══ 19.569. EDC3165 ═══ Null statement. Possible extraneous semi-colon. Recovery: Check for extra semi-colons in statement. ═══ 19.570. EDC3166 ═══ Bit-field "&1" cannot be used in a conditional expression that is to be modified. The bit-field is part of a conditional expression that is to be modified. Only objects that can have their address taken are allowed as part of such an expression. Recovery: Remove the bit-field from the conditional expression. ═══ 19.571. EDC3167 ═══ The "&1" qualifier cannot be applied to "&2". The qualifier is being applied to a name or a type for which it is not valid. Recovery: Remove the qualifier. ═══ 19.572. EDC3168 ═══ Local type "&1" cannot be used as a &2 argument. The type is declared within the scope of a function, and is being used as a function argument or as a type in the instantiation of a template. Recovery: Remove the local type from the instantiation. ═══ 19.573. EDC3169 ═══ Exception specification for function "&1" does not match previous declaration. If an exception specification is given in more than one declaration of a function, it must be the same in all such declarations. Recovery: Ensure that all exception specifications match. ═══ 19.574. EDC3170 ═══ Default initializers for non-type template arguments are only allowed for class templates. Default initializers have been given for non-type template arguments but the template is not declaring a class. Recovery: Remove the default initializers. ═══ 19.575. EDC3171 ═══ A function argument must not have type "void". A function argument may be an expression of any object type. "void" is an incomplete type that cannot be completed. Object types and incomplete types are disjoint sets. Recovery: Change the return type of the function argument. ═══ 19.576. EDC3172 ═══ Insufficient memory in line &1 of file "&2". The compiler ran out of memory during compilation. Recovery: End unnecessary processes and recompile. ═══ 19.577. EDC3173 ═══ SIGDANGER received: page space low, compilation stopping. The operating system is about to run out of memory. The compiler will exit to return memory to the system. Recovery: End unnecessary processes and recompile. ═══ 19.578. EDC3174 ═══ An object of abstract class "&1" cannot be created. Objects of an abstract class cannot be created except as objects representing a base class of a class derived from it. A class is abstract if it has at least one pure virtual function. Recovery: Derive another object from the abstract class. ═══ 19.579. EDC3175 ═══ Invalid use of an abstract class. An abstract class must not be used as an argument type, as a function return type, or as the type of an explicit conversion. Recovery: Derive another class from the abstract, instantiate it so it becomes a concrete object, and then use it instead. ═══ 19.580. EDC3176 ═══ "&1" has been used more than once in the same base class list. A base class may only be specified once in the base class list for a derived class. Recovery: Remove one of the specifications. ═══ 19.581. EDC3177 ═══ Template argument &1 of type "&2" does not match declared type "&3". A non-type template argument must have a type that exactly matches the type of the corresponding argument in the template declaration. Recovery: Ensure that the types match. ═══ 19.582. EDC3178 ═══ Template argument &1 of type "&2" is not an allowable constant value or address. A non-type template argument must be a constant value or the address of a global object, function or static data member. Recovery: Change the template argument. ═══ 19.583. EDC3179 ═══ Template argument list is empty. At least one template argument must be specified in a template declaration. Recovery: Specify a template argument in the declaration. ═══ 19.584. EDC3180 ═══ Template argument &1 is of type "&2" which is not an integral or pointer type. A non-type template argument must be of integral or pointer type, so that it can be matched with a constant integral value. Recovery: Change the template argument. ═══ 19.585. EDC3181 ═══ "&1" is defined in a template declaration but it is not a static member. A member of a template class defined in a template declaration must be a static member. Recovery: Make the member static or remove it from the template declaration. ═══ 19.586. EDC3182 ═══ Template argument "&1" is not used in the declaration of "&2". All template arguments for a non-class template must be used in the declaration of the name or the function argument list. Recovery: Ensure all template arguments are used in the declaration of the name or the function argument list. ═══ 19.587. EDC3183 ═══ Template declaration does not declare a class, a function, or a template class member. A template declaration must declare a class, a function, or a static data member of a template class, following the template arguments. Recovery: Change the template declaration to declare a class, a function, or a template class member. ═══ 19.588. EDC3184 ═══ Return type "&1" for function "&2" differs from previous return type of "&3". The declaration of the function differs from a previous declaration in only the return type. Recovery: Change the return type so that it matches the previous return type. ═══ 19.589. EDC3185 ═══ "&1" is a member of "&2" and cannot be used without qualification. The specified name is a class member, but no class qualification has been used to reference it. Recovery: Add a class qualification to the class member. ═══ 19.590. EDC3186 ═══ The expression is not a valid preprocessor constant expression. The expression in an "#if" or "#elif" preprocessor directive is either not a valid expression or not a constant expression. No keywords are recognized in such an expression and non-macro identifiers are replaced by the constant 0. Recovery: Change the expression for the preprocessor directive. ═══ 19.591. EDC3187 ═══ "&1" cannot be initialized multiple times. An initializer was already specified in the constructor definition. Recovery: Remove the additional initializer. ═══ 19.592. EDC3188 ═══ A macro parameter is expected after the "#" operator. The "#" operator in a macro replacement list must be followed by a macro parameter. Recovery: Add a macro parameter after the "#" operator. ═══ 19.593. EDC3189 ═══ "##" operator is at the start or end of the replacement list. The "##" operator must be preceded and followed by valid tokens in the macro replacement list. Recovery: Move the "##" operator in the replacement list. ═══ 19.594. EDC3190 ═══ One or more "#endif" statements are missing at end of file. The end of file has been reached and there are still "#if", "#ifdef" or "#ifndef" statements without a matching "#endif" statement. Recovery: Ensure that all "#if", "#ifdef", and "#ifndef" statements have matching "#endif" statements. ═══ 19.595. EDC3191 ═══ No suitable copy assignment operator exists to perform the assignment. A copy assignment operator exists but it does not accept the type of the given parameter. Recovery: Change the copy assignment operator. ═══ 19.596. EDC3192 ═══ Identifier "&1" in preprocessor expression is assigned 0. Identifiers are not recognized in a preprocessor expression. The specified identifier has been treated as a non-macro identifier and assigned the constant 0. ═══ 19.597. EDC3193 ═══ Explicit call to constructor "&1" is not allowed. A constructor cannot be called explicitly. It is called implicitly when an object of the class is created. Recovery: Remove the call to the constructor. ═══ 19.598. EDC3194 ═══ "catch(&1)" will never be reached because of previous "catch(&2)". The catch clause can never be reached since any exception type that matches it will also be matched by the specified previous catch clause. Recovery: Change or remove one of the catch clauses. ═══ 19.599. EDC3195 ═══ No default constructor exists for "&1". An array of class objects must be initialized by calling the default constructor but one has not been declared. Recovery: Declare a default constructor for the array. ═══ 19.600. EDC3196 ═══ More than one default constructor exists for "&1". An array of class objects must be initialized by calling the default constructor but the call is ambiguous. Recovery: Ensure that only one default constructor exists. ═══ 19.601. EDC3197 ═══ It is invalid to have a throw expression with type "&1". Recovery: Change the type or remove the throw expression. ═══ 19.602. EDC3198 ═══ The exception specification is ignored in this declaration. The declaration contains a function declarator with an exception specification but is not the declaration of a function. The exception specification is ignored. Recovery: Change the function declarator so that it is the declaration of a function. ═══ 19.603. EDC3199 ═══ The compiler cannot generate a default copy constructor for "&1". The default copy constructor cannot be generated for this class because there exists a member or base class that has a private copy constructor, or there are ambiguous base classes, or this class has no name. Recovery: Ensure that a member or base class does not have a private copy constructor. If not then ensure the class is named and there are no ambiguous references to base classes. ═══ 19.604. EDC3200 ═══ The compiler cannot generate a default copy assignment operator for "&1". The default copy assignment operator cannot be generated for this class because it has a const member or a reference member or a member (or base class) with a private copy assignment operator. Recovery: Ensure there are no const members, reference members or members with a private copy assignment operator. ═══ 19.605. EDC3201 ═══ &1 too few non-option arguments. Recovery: Add non-option arguments. ═══ 19.606. EDC3202 ═══ "main" must not be declared inline or static. Although "main" is not a keyword, it is a special function that cannot be inlined or declared static. Recovery: Remove the inline or static specifier from the declaration of main. ═══ 19.607. EDC3203 ═══ Pure virtual function called. A call has been made to a pure virtual function from a constructor or destructor. In such functions, the pure virtual function would not have been overridden by a derived class and a run-time error would occur. Recovery: Remove the call to the pure virtual function. ═══ 19.608. EDC3204 ═══ "&1" is not allowed as a conversion function type. A conversion function cannot be declared with a function or an array as its conversion type, since the type cannot be returned from the function. Recovery: Declare the function as converting to a pointer to the function or the array element type. ═══ 19.609. EDC3205 ═══ Syntax error - "&1" is followed by "&3" but is not the name of a &2. The name is not a class or template name but the context implies that it should be. Recovery: Change the name to a class or template name. ═══ 19.610. EDC3206 ═══ The previous &1 messages apply to the definition of template "&2". The instantiation of the specified template caused the messages, even though the line numbers in the messages refer to the original template declaration. Recovery: Ensure this is the desired response. ═══ 19.611. EDC3207 ═══ The previous message applies to the definition of template "&1". The instantiation of the specified template caused the message, even though the line number in the message refers to the original template declaration. Recovery: Ensure this is the desired response. ═══ 19.612. EDC3208 ═══ No suitable constructor exists for conversion from "&1" to "&2". A constructor is required for the class but no user-defined constructor exists and the compiler could not generate one. Recovery: Create a suitable constructor for conversion. ═══ 19.613. EDC3209 ═══ class "&1" does not have a copy assignment operator. A copy assignment operator is required for the class but no user-defined copy assignment operator exists and the compiler could not generate one. Recovery: Create a copy assignment operator. ═══ 19.614. EDC3210 ═══ "&1" cannot be used as a template name since it is already known in this scope. A template name must not match the name of an existing template, class, function, object, value or type. Recovery: Change one of the template names. ═══ 19.615. EDC3211 ═══ "&1" is expected for template argument &2. Either the argument is a type and the template has a non-type argument or the argument is an expression and the template has a type argument. Recovery: Ensure the argument matches the template. ═══ 19.616. EDC3212 ═══ "&1" cannot be defined before the template definition of which it is an instance. An explicit definition of a template class cannot be given before the corresponding template definition. Recovery: Move the template definition so that it occurs before any template class definitions. ═══ 19.617. EDC3213 ═══ An ellipsis (...) cannot be used in the argument list of a template function. Since an exact match is needed for template functions, an ellipsis cannot be used in the function argument list. Recovery: Remove the ellipsis from the argument list. ═══ 19.618. EDC3214 ═══ The suffix for the floating point constant is not valid. Recovery: Change the suffix for the floating point constant. ═══ 19.619. EDC3215 ═══ Statement has no effect. The expression has no side effects and produces a result that is not used. Recovery: Remove the statement or use its result. ═══ 19.620. EDC3216 ═══ "/*" detected in comment. "/*" has been detected within a "/*" type comment. Nested comments are not allowed. Recovery: Remove the imbedded "/*". ═══ 19.621. EDC3217 ═══ Predefined macro name "&1" cannot be redefined or undefined. The specified macro name is predefined by the compiler and cannot be redefined with #define or undefined with #undef. Recovery: Remove the definition expression. ═══ 19.622. EDC3218 ═══ The suffix for the integer constant is not valid. The integer constant is a suffix letter that is not recognized as a valid suffix. Recovery: Change the suffix to either "u" or "l". ═══ 19.623. EDC3219 ═══ The expression contains a division by zero. Recovery: Remove the division by zero from the expression. ═══ 19.624. EDC3220 ═══ The expression contains a modulus by zero. Recovery: Remove the modulus by zero from the expression. ═══ 19.625. EDC3221 ═══ Static member "&1" can only be defined at file scope. Recovery: Move the static member so that it is defined at file scope. ═══ 19.626. EDC3222 ═══ "&1" needs a constructor because &2 "&3" needs a constructor initializer. Recovery: Add a constructor. ═══ 19.627. EDC3223 ═══ "&1" cannot be redeclared since it has already been used in this scope. The name is being declared in a member list but was previously declared outside the member list and then used in the member list. Recovery: Change or remove one of the occurrences. ═══ 19.628. EDC3224 ═══ Conversion from "&1" to a reference to a non-const type "&2" requires a temporary. A temporary may only be used for conversion to a reference type when the reference is to a const type. Recovery: Change to a const type. ═══ 19.629. EDC3225 ═══ "&2" is too small to hold a value of type "&1". A conversion from a pointer type to an integral type is only valid if the integral type is large enough to hold the pointer value. Recovery: Remove the conversion from a pointer type to an integral type. ═══ 19.630. EDC3226 ═══ Object of type "&1" cannot be constructed from "&2" expression. There is no constructor taking a single argument that can be called using the given expression. Recovery: Change the expression. ═══ 19.631. EDC3227 ═══ The compiler cannot generate a copy constructor for conversion to "&1". A copy constructor is required for the conversion. No suitable user-defined copy constructor exists and the compiler could not generate one. Recovery: Create a copy constructor for the conversion. ═══ 19.632. EDC3228 ═══ No suitable constructor or conversion function exists for conversion from "&1" to "&2". A constructor or conversion function is required for the conversion but no such constructor or function exists. Recovery: Create a constructor or conversion function for the conversion. ═══ 19.633. EDC3229 ═══ The file is empty. Recovery: Check the file name. ═══ 19.634. EDC3230 ═══ Syntax error - "&1" has been inserted before "&2". A syntax error was found while parsing the program. The message identifies what the compiler expected and what it actually found. The compiler inserts the expected value and compilation continues. Recovery: Correct the syntax. ═══ 19.635. EDC3231 ═══ Call to "&1" matches some functions best in some arguments, but no function is a best match for all arguments. No function matches each call argument as well as or better than all other functions. Recovery: Change the function call so that it matches only one function. ═══ 19.636. EDC3232 ═══ Call matches "&1". The compiler detected an overloaded function or operator that is similar to another and is providing additional information. Recovery: Ensure this is the desired match. ═══ 19.637. EDC3233 ═══ Cannot adjust access of "&1::&2" because a member in "&3" hides it. The specified member cannot have its access modified because a member of the same name in the specified class hides it. Recovery: Remove the access adjustment expression or unhide the member. ═══ 19.638. EDC3234 ═══ "&1" cannot be redeclared. The specified name cannot be redeclared because it has already been used. Recovery: Change or remove one of the declarations. ═══ 19.639. EDC3235 ═══ Syntax error - "&1" is not allowed; "&2" has already been specified. The specified attributes are both part of a declaration and are not allowed to be specified in the same declaration. Recovery: Remove the attributes. ═══ 19.640. EDC3236 ═══ Missing option to "#pragma &1"; the directive is ignored. Recovery: Ensure all options for the "#pragma" are present. ═══ 19.641. EDC3237 ═══ Invalid option "&1" specified for "#pragma options"; the option is ignored. Recovery: Remove the invalid option. ═══ 19.642. EDC3238 ═══ Invalid or out of range pragma parameter; parameter is ignored. Recovery: Remove the parameter or replace it with one within the range. ═══ 19.643. EDC3239 ═══ Function "&1" has internal linkage but is undefined. If a static function or inline member function is referenced in this compilation unit it must be defined in the same compilation unit. Recovery: Define the function in the same compilation unit it is referenced in. ═══ 19.644. EDC3240 ═══ Call to "&1" matches more than one template function. More than one template for the function matches equally well with the argument list specified on the call. Recovery: Change the call so that it only matches one template function. ═══ 19.645. EDC3241 ═══ "&1" was declared with external linkage and called before it is defined as inline. When no inline specifier is used, linkage will be external unless an inline definition appears before the first call. Recovery: Define the function before the first call to it. ═══ 19.646. EDC3242 ═══ Non-&1 member function called for a &1 object via pointer of type "&2". The member function is being called for a const or volatile object but it has not been declared with the corresponding const or volatile attribute. Recovery: Ensure that the function call and the function declaration match. ═══ 19.647. EDC3243 ═══ "&1" cannot be a base of "&2" because "&3" contains the type name "&2". A class cannot inherit a type name that is the same as the class name. Recovery: Change the name of either the derived class or the inherited class. ═══ 19.648. EDC3244 ═══ "&1" cannot be a base of "&2" because "&3" contains the enumerator "&2". A class cannot inherit an enumerator with the same name as the class name. Recovery: Change the name of either the derived class or the inherited enumerator name. ═══ 19.649. EDC3245 ═══ "&1" cannot be a base of "&2" because "&3" contains an anonymous union member "&2". A class cannot inherit an anonymous union member with the same name as the class name. Recovery: Change either the name of the derived class or the inherited anonymous union member. ═══ 19.650. EDC3246 ═══ Symbol length of &1 exceeds limit of &2 bytes. Recovery: Shorten the symbol length. ═══ 19.651. EDC3247 ═══ The result of this pointer to member operator can be used only as the operand of the function call operator (). If the result of the .* or ->* is a function, then that result can be used only as the operand for the function call operator (). Recovery: Make the result of the pointer to member operator the operand of the function call operator (). ═══ 19.652. EDC3248 ═══ When "&1" is used as an operand to the arrow or dot operator the result must be used with the function call operator (). If the result of the dot or arrow operator is a function, then that result can be used only as the operand for the function call operator (). Recovery: Make the result the operand of the function call operator (). ═══ 19.653. EDC3249 ═══ A class with a reference or const member needs a constructor. const and reference members must be initialized in a constructor initializer list. Recovery: Add a constructor to the class. ═══ 19.654. EDC3250 ═══ Base class initializers cannot contain virtual function calls. The virtual function table pointers are not set up until after the base classes are initialized. Recovery: Remove the call to a virtual function in the base class initializer. ═══ 19.655. EDC3251 ═══ The previous declaration of "&1" did not have a linkage specification. A function declaration without a linkage specification must not precede the first linkage specification for that function. Recovery: Add a linkage specification to the first declaration of the function ═══ 19.656. EDC3252 ═══ The destructor for "&1" does not exist. The call is ignored. The destructor call is for a type that does not have a destructor. The call is ignored. Recovery: Add a destructor to the type. ═══ 19.657. EDC3253 ═══ "&1" has been added to the scope of "&2". Because the friend class has not been declared yet, its name has been added to the scope of the class containing the friend declaration. Recovery: If this is not intended, move the declaration of the friend class so that it appears before it is declared as a friend. ═══ 19.658. EDC3254 ═══ The body of friend member function "&1" cannot be defined in the member list of "&2". A friend function that is a member of another class cannot be defined inline in the member list. Recovery: Define the body of the friend function at file scope. ═══ 19.659. EDC3255 ═══ The initializer list must be complete because "&1" does not have a default constructor. Recovery: Complete the initializer list or add a default constructor to the class. ═══ 19.660. EDC3256 ═══ "&1" cannot be opened. The nested include file limit of &2 has been exceeded. Recovery: Remove the nesting of one or more of the include files. ═══ 19.661. EDC3257 ═══ An anonymous union at file scope must have a storage class of static. Recovery: Change the storage class of the anonymous union to static. ═══ 19.662. EDC3258 ═══ A pure virtual destructor needs an out-of-line definition in order for the corresponding class to be a base of another class. Recovery: Move the definition of the pure virtual destructor so that it is out of line. ═══ 19.663. EDC3259 ═══ The initializer is improperly braced. Recovery: Correct the braces on the initializer. ═══ 19.664. EDC3260 ═══ Invalid octal integer constant. The octal integer constant contains an '8' or a '9'. Recovery: Ensure that the octal integer constant is valid. ═══ 19.665. EDC3261 ═══ All the arguments must be specified for "&1" because its default arguments have not been checked yet. For member functions, names in default argument expressions are bound at the end of the class declaration. Calling a member function as part of a second member function's default argument is an error if the first member function's default arguments have not been checked and the call does not specify all of the arguments. Recovery: Specify all the arguments for the function. ═══ 19.666. EDC3262 ═══ Ellipsis (...) cannot be used for "&1". Recovery: Remove the ellipsis. ═══ 19.667. EDC3263 ═══ Syntax error - expected "&1" or "&2" and found "&3". A syntax error was found while parsing the program. The message identifies what the compiler expected and what it actually found. Recovery: Correct the syntax error. ═══ 19.668. EDC3264 ═══ A character constant must end before the end of the line. Recovery: End the character constant before the end of the line or use the continuation "/" symbol. ═══ 19.669. EDC3265 ═══ A virtual function initializer must be 0. Recovery: Set the virtual function initializer to 0. ═══ 19.670. EDC3266 ═══ "&1" is given "&2" access. Recovery: Ensure this change is intended. ═══ 19.671. EDC3267 ═══ "&1" has been qualified with the "this" pointer. Recovery: Ensure this qualification is intended. ═══ 19.672. EDC3268 ═══ Invalid escape sequence; the backslash is ignored. Recovery: Ensure the escape sequence is valid. ═══ 19.673. EDC3269 ═══ The result of an address expression is being deleted. Recovery: Ensure this action is intended. ═══ 19.674. EDC3270 ═══ Conversion from "&1" to "&2" matches more than one conversion function. More than one conversion function could be used to perform the specified conversion. Recovery: Create a new conversion function for this conversion or change one of the types. ═══ 19.675. EDC3271 ═══ Conversion matches "&1". Recovery: Ensure this is the intended match. ═══ 19.676. EDC3272 ═══ "&1" cannot be initialized with an initializer list. Only an object of a class with no constructors, no private or protected members, no virtual functions and no base classes can be initialized with an initializer list. Recovery: Remove the class from the initializer list. ═══ 19.677. EDC3273 ═══ A pointer to a virtual base "&1" cannot be converted to a pointer to a derived class "&2". A pointer to a class B may be explicitly converted to a pointer to a class D that has B as a direct or indirect base class if an unambiguous conversion from D to B exists and if B is not a virtual base class. Recovery: Remove the conversion of the pointer. ═══ 19.678. EDC3274 ═══ The arguments passed using the ellipsis may not be accessible. Arguments passed using an ellipsis are only accessible if there is an argument preceding the ellipsis and the preceding argument is not passed by reference. Recovery: Ensure that there is an argument preceding the ellipsis and that the preceding argument is not passed by reference. ═══ 19.679. EDC3275 ═══ Member function "&1" has already been declared. A member function cannot be redeclared in the class definition. Recovery: Remove one of the declarations. ═══ 19.680. EDC3276 ═══ Assignment to a constant expression is not allowed. Recovery: Remove the assignment. ═══ 19.681. EDC3277 ═══ Assignment to const variable "&1" is not allowed. Recovery: Remove the assignment to the const variable. ═══ 19.682. EDC3278 ═══ Syntax error found while parsing the bit-field declarator. Recovery: Correct the syntax error. ═══ 19.683. EDC3279 ═══ The return type for the "operator->" cannot be the containing class. Recovery: Change the return type for the "operator->". ═══ 19.684. EDC3280 ═══ The virtual function table for "&1" is defined with "&2" linkage. Recovery: Ensure this is the desired result. ═══ 19.685. EDC3281 ═══ The virtual function table for "&1" will be defined where "&2" is defined. Recovery: Ensure this is the desired result. ═══ 19.686. EDC3282 ═══ The virtual function table for "&1" will be defined in a file specified by the user. Recovery: Ensure this is the desired result. ═══ 19.687. EDC3283 ═══ The previous message applies to function argument &1. The previous message applies to the specified argument number. ═══ 19.688. EDC3284 ═══ Conversion from "&1" to a reference to a non-const type "&2" requires a temporary. Recovery: Change the reference so that it is to a const type. ═══ 19.689. EDC3285 ═══ The address of a local variable or compiler temporary is being used in a return expression. The address of a local variable may not be valid once control is passed out of the function. Recovery: Declare the variable in the calling function or as a global variable. ═══ 19.690. EDC3286 ═══ Keyword "&1" cannot be used with a function definition. Recovery: Remove the keyword. ═══ 19.691. EDC3287 ═══ The directive must occur before the first C++ statement in program; "#pragma" is ignored. Recovery: Remove the directive or place it before the first C++ statement in the program. ═══ 19.692. EDC3288 ═══ The pointer to member function must be bound to an object or a pointer to an object when it used with the function call operator (). Recovery: Remove the pointer. ═══ 19.693. EDC3289 ═══ The static data member "&1" has already been declared. Recovery: Remove or change one of the declarations. ═══ 19.694. EDC3290 ═══ Option "&1" must be specified on the command line or before the first C++ statement in the program. Recovery: Remove the option or place it before the first statement in the C++ program. ═══ 19.695. EDC3291 ═══ The direct base "&1" of class "&2" is ignored because "&1" is also an indirect base of "&2". A reference to a member of "&1" will be ambiguous. Recovery: Remove the indirect inheritance. ═══ 19.696. EDC3292 ═══ The "&1" operator cannot be applied to undefined class "&2". A class is undefined until the definition of its tag has been completed. A class tag is undefined when the list describing the name and type of its members has not been specified. The definition of the tag must be given before the operator is applied to the class. Recovery: Complete the definition of the class before applying an operator to it. ═══ 19.697. EDC3293 ═══ "&1" hides the &2 "&3". A member in the derived class hides a virtual function member in a base class. Recovery: Ensure the hiding of the virtual function member is intended. ═══ 19.698. EDC3294 ═══ "&1" is not the name of a function. A function name is required in this context. The specified name has been declared but it is not the name of a function. Recovery: Check the spelling. If necessary, change to a function name. ═══ 19.699. EDC3295 ═══ "&1" is not the name of a variable that may be used in a "#pragma disjoint" directive. The variable must not be a class member or an enumeration constant. Recovery: Ensure that the variable is not a class member or an enumeration constant. ═══ 19.700. EDC3296 ═══ The virtual functions "&1" and "&2" are ambiguous since they override the same function in virtual base class "&3". The two functions are ambiguous and the virtual function call mechanism will not be able to choose at run-time. Recovery: Remove one of the virtual functions. ═══ 19.701. EDC3297 ═══ The "this" address for "&1" is ambiguous because there are multiple instances of "&2". Two or more "this" addresses are possible for this virtual function. The virtual function call mechanism will not be able to determine the correct address at run-time. Recovery: Remove the "this" expression or change the function name. ═══ 19.702. EDC3298 ═══ Conversion from "&1" matches more than one conversion function. More than one conversion function could be applied to perform the conversion from the specified type. Recovery: Create a new conversion function or remove the conversion. ═══ 19.703. EDC3299 ═══ Function "&1" must not be declared as "&2". The specified function has a storage class that is not allowed in the context that the function is declared in. Recovery: Remove the declaration or change the storage class of the function. ═══ 19.704. EDC3300 ═══ The declaration of "&1" must initialize the const member "&2". Recovery: Initialize the member in the declaration. ═══ 19.705. EDC3301 ═══ The declaration of "&1" must initialize the reference member "&2". Recovery: Initialize the member in the declaration. ═══ 19.706. EDC3302 ═══ "&1" is not allowed as a function return type. There may be a ";" missing after a "}". A class or enum definition must not be specified as a function return type. A semicolon may be missing after the definition. Recovery: Ensure that a semicolon is not missing after the definition or change the return type. ═══ 19.707. EDC3303 ═══ "&1" cannot be a base of "&2" because "&3" contains a member function called "&2". A class cannot inherit a function that has the same as the class. Recovery: Change the name of either the base class or the inherited function. ═══ 19.708. EDC3304 ═══ Forward declaration of the enumeration "&1" is not allowed. Recovery: Fully declare the enumeration. ═══ 19.709. EDC3305 ═══ Unrecognized value "&1" specified with option "&2". Recovery: Remove the unrecognized value. ═══ 19.710. EDC3306 ═══ The previous message applies to argument &1 of function "&2". The previous message applies to the specified argument number. ═══ 19.711. EDC3307 ═══ Unrecognized pragma "&1". The pragma is not supported by this compiler. Recovery: Change or remove the #pragma directive. ═══ 19.712. EDC3308 ═══ The nested class object "&1" needs a constructor so that its &2 members can be initialized. Recovery: Create a constructor for the nested class object. ═══ 19.713. EDC3309 ═══ The integer constant is out of range. Recovery: Ensure the integer constant is in range. ═══ 19.714. EDC3310 ═══ The floating point constant is out of range. Recovery: Ensure the floating point constant is in range. ═══ 19.715. EDC3311 ═══ The &1 member "&2" must be initialized in the constructor's initializer list. Using the constructor's member initializer list is the only way to initialize nonstatic const and reference members. Recovery: Initialize the member in the constructor's initializer list. ═══ 19.716. EDC3312 ═══ Unexpected end of file: newline expected. The file did not end with a newline character. Recovery: Ensure the file ends with a newline character. ═══ 19.717. EDC3313 ═══ Constructors and conversion functions are not considered when resolving an explicit cast to a reference type. ═══ 19.718. EDC3314 ═══ A character string literal cannot be concatenated with a wide string literal. A string that has a prefix L cannot be concatenated with a string that is not prefixed. Recovery: Ensure both strings have the same prefix, or no prefix at all. ═══ 19.719. EDC3315 ═══ All members of type "&1" must be explicitly initialized with all default arguments specified because the default arguments for "&2" have not been checked yet. Default arguments for member functions are not checked until the end of the class definition. Default arguments for member functions of nested classes are not semantic checked until the containing class is defined. A call to a member function before its default arguments have been checked must specify all arguments. Recovery: Specify all default arguments with all members of the type. ═══ 19.720. EDC3316 ═══ The nested class "&1" is undefined and cannot be defined later. A class must be defined in the scope that it was introduced. Recovery: Define the class in the scope that it was introduced in. ═══ 19.721. EDC3317 ═══ The address of an overloaded function can be taken only in an initialization or an assignment. Recovery: Ensure the address of an overloaded function is used on an initialization or an assignment. ═══ 19.722. EDC3318 ═══ The compiler cannot recover from the previous errors. Recovery: Fix the errors and try the compile again. ═══ 19.723. EDC3319 ═══ The mangled name for "&1" contains a compiler generated name. The mangled name will not be visible from other compilation units. ═══ 19.724. EDC3320 ═══ Syntax error - found "&1 &2" : "&1" is not a type name. Recovery: Change to a type name or remove the expression. ═══ 19.725. EDC3321 ═══ A temporary of type "&1" is needed: "&2" is an abstract class. Recovery: Ensure this is the desired result. ═══ 19.726. EDC3322 ═══ Nesting level of template class definitions may cause the compiler to fail. Template class definitions are nested in such a way that the compiler may not be able to continue. Recovery: Reduce the number of nesting levels of template class definitions. ═══ 19.727. EDC3323 ═══ "&1" hides pure virtual function "&2" in the nonvirtual base "&3". The pure virtual function in a nonvirtual base cannot be overridden once it has been hidden. Recovery: Ensure this is the desired result. If this is not intended, unhide the pure virtual function. ═══ 19.728. EDC3324 ═══ The class qualifier "&1" for "&2" must be a template class that uses the template arguments. A non-class template can only declare a global function or a member of a template class. If it declares a member of a template class, the template class arguments must include at least one of the non-class template arguments. Recovery: Change the template declaration so that it either declares a global function or a member of a template class that uses the non-class template arguments. ═══ 19.729. EDC3325 ═══ The class "&1" cannot be passed by value because it does not have a copy constructor. Recovery: Create a copy constructor for the class or change the argument to pass by variable. ═══ 19.730. EDC3326 ═══ The previous &1 messages show situations that could arise if the corresponding template definitions were instantiated. During the processing of a class template, possible errors were found in the class declaration. These errors may occur when the template is instantiated. Recovery: Ensure that the errors will not occur when the template is instantiated. ═══ 19.731. EDC3327 ═══ The previous message shows a situation that could arise if the corresponding template definition was instantiated. During the processing of a class template, a possible error was found in the class declaration. This error may occur when the template is instantiated. Recovery: Ensure that the error will not occur when the template is instantiated. ═══ 19.732. EDC3328 ═══ The output file name "&1" cannot be the same as the input file name. Recovery: Change either the input file name or the output file name. ═══ 19.733. EDC3329 ═══ The external variable "&1" cannot be defined at block scope. Recovery: Move the external variable definition. ═══ 19.734. EDC3330 ═══ "&1" cannot have an initializer list. Recovery: Remove the initializer list. ═══ 19.735. EDC3331 ═══ Return value of type "&1" is expected. No return value is being returned from the current function but the function is expecting a non-void return value. Recovery: Ensure a return value will be returned or change the return value of the function. ═══ 19.736. EDC3332 ═══ "&1" bypasses initialization of "&2". It is invalid to jump past a declaration with an explicit or implicit initializer unless the declaration is in an inner block that is also jumped past. Recovery: Enclose the initialization in a block statement. ═══ 19.737. EDC3333 ═══ "&1" is being redeclared as a member function. It was originally declared as a data member. The template redeclares a data member of a class template as a member function. Recovery: Change the original declaration to a member function or change the redeclaration to a data member. ═══ 19.738. EDC3334 ═══ "&1" is being redeclared as a non-function member or has syntax errors in its argument list. The template redeclares a member function of a class template as a data member. There may be syntax errors in the declaration. ═══ 19.739. EDC3335 ═══ A string literal cannot be longer than &1 characters. Recovery: Specify a shorter string literal. ═══ 19.740. EDC3336 ═══ A wide string literal cannot be longer than &1 characters. Recovery: Specify a shorter string literal. ═══ 19.741. EDC3337 ═══ The definition of "&1" is not contained in an include file, but it may be needed for automatic generation of template functions. The definition of the class can only be used during automatic generation of template functions if it is contained in an include file. Recovery: Add the definition to an include file. ═══ 19.742. EDC3338 ═══ Invalid MBCS character. Recovery: Replace the MBCS character. ═══ 19.743. EDC3339 ═══ "&1" is an undefined pure virtual function. Recovery: Remove or define as a pure virtual function. ═══ 19.744. EDC3340 ═══ The presence of the "#line" directive in source files compiled with "-a" or "-ae" may result in the "tcov" program behaving unpredictably. Recovery: Remove the "#line" directive or recompile without the "-a" or "-ae" option. ═══ 19.745. EDC3341 ═══ Missing value for option "&1". Recovery: Add a value for the option. ═══ 19.746. EDC3342 ═══ Template "&1" cannot be instantiated because the actual argument for formal argument "&2" has more than one variant. The argument is a function template or an overloaded function with two or more variants. The compiler cannot decide which variant to choose to bind to the argument type. Recovery: Change the formal template argument or remove the extra variants. ═══ 19.747. EDC3343 ═══ More than 32760 files in a compilation unit. Recovery: Reduce the number of files. ═══ 19.748. EDC3345 ═══ Pointer to a builtin function not allowed. The address of a builtin function cannot be taken therefore the compiler does not allow for the declaration of a pointer to a builtin function. Recovery: Remove the pointer. ═══ 19.749. EDC3346 ═══ Builtin function "&1" not recognized. The function declared as a builtin is not recognized by the compiler as being a builtin function. Recovery: Ensure the function is a builtin function or remove the builtin keyword from the declaration. ═══ 19.750. EDC3347 ═══ "&1" is not supported. Recovery: Remove the operator from the expression. ═══ 19.751. EDC3348 ═══ Function calls are not supported. Recovery: Remove function calls from the expression. ═══ 19.752. EDC3349 ═══ The expression is too complicated. Recovery: Simplify the expression. ═══ 19.753. EDC3350 ═══ Evaluation of the expression requires a temporary. Recovery: Change the expression so that a temporary is not required. ═══ 19.754. EDC3351 ═══ "&1" is an overloaded function. The identifier refers to an overloaded function with two or more variants. The compiler requires a prototype argument list to decide which variant to process. Recovery: Specify a prototype argument list or remove variants of the overloaded function. ═══ 19.755. EDC3352 ═══ Identifier or function prototype expected. The symbol must be the name of a data object, the name of a function with no variants, or a function or operator name followed by a parenthesized argument list. Recovery: Ensure the symbol is either the name of a data object, the name of a function with no variants, or a function or operator name followed by a parenthised argument list. ═══ 19.756. EDC3353 ═══ "&1" does not have external linkage. The pragmas map, import, and export can only be applied to objects or functions that are external. Recovery: Give the identifier external linkage. ═══ 19.757. EDC3354 ═══ "&1" has already been mapped. Only one map name may be given to any object or function. Recovery: Change one of the map names. ═══ 19.758. EDC3355 ═══ BII file name cannot be found in the BII table for function &1. The BII file name cannot be found in the BII table. Recovery: Check the spelling of the file name. ═══ 19.759. EDC3356 ═══ Invalid option with #pragma. The option given with #pragma is invalid. Recovery: Remove the #pragma option. ═══ 19.760. EDC3357 ═══ BII function name already exists in the BII table for function &1. The BII function name already exists in the BII table. Recovery: Change the file name. ═══ 19.761. EDC3358 ═══ The "&1" option is not allowed with the "&2" option. The specified options cannot be specified together. The first is ignored. Recovery: Remove one of the options. ═══ 19.762. EDC3359 ═══ The result of string concatenation is a non-Pascal string. A pascal string was concatenated to a non-Pascal string. The result of the concatenation is a non-Pascal string. Recovery: Ensure both strings are either Pascal or non-Pascal. ═══ 19.763. EDC3360 ═══ The result of string concatenation is a Pascal string. A non-Pascal string was concatenated to a Pascal string. The result of the concatenation is a Pascal string. Recovery: Ensure both strings are either Pascal or non-Pascal. ═══ 19.764. EDC3361 ═══ A Pascal string is too long; the length has been set to 255. A Pascal string is longer than 255 bytes. The length byte has been set to 255, but the rest of the string is left intact. Recovery: Shorten the Pascal string. ═══ 19.765. EDC3362 ═══ The bit-field length must not be negative. The bit-field length must be a non-negative integer value. Recovery: Change the bit-field length to a non-negative integer value. ═══ 19.766. EDC3363 ═══ The bit-field length must not be negative. The bit-field length must be a non-negative integer value. Recovery: Change the bit-field length to a non-negative integer value. ═══ 19.767. EDC3364 ═══ A zero-length bit-field must not have a name. A named bit-field must have a positive length; a zero-length bit-field is used for alignment only, and must not be named. Recovery: Remove the name from the zero-length bit-field. ═══ 19.768. EDC3365 ═══ The bit-field is too small; &1 bits are needed for "&2". The bit-field length is smaller than the number of bits needed to hold all values of the enum. Recovery: Increase the bit-field length. ═══ 19.769. EDC3366 ═══ The bit-field is larger than necessary; only &1 bits are needed for "&2". The bit-field length is larger than the number of bits needed to hold all values of the enum. Recovery: Decrease the bit-field length. ═══ 19.770. EDC3367 ═══ An object declared as compatible with 16-bit applications is larger than 64K. The name of the object, or a typedef name used to declare it, appeared in a #pragma seg16 directive. Recovery: Remove the name of an object in the #pragma seg16 directive. ═══ 19.771. EDC3370 ═══ A template friend declaration may only declare, not define, a class or function. The class or function declared in the template friend declaration must be defined at file scope. Recovery: Remove the definition from the template friend declaration. ═══ 19.772. EDC3371 ═══ The function "&1" must not be declared "&2" at block scope. There can be no static or inline function declarations at block scope. Recovery: Move the function so that it is not defined at block scope. ═══ 19.773. EDC3372 ═══ The previous &1 messages apply to function argument &2. The previous messages apply to the specified argument number. ═══ 19.774. EDC3373 ═══ The previous &1 messages apply to argument &2 of function "&3". The previous messages apply to the specified argument number. ═══ 19.775. EDC3374 ═══ "&1" is not a static member of "&2". Non-static data members cannot be defined outside the class definition. Recovery: Make the member a static member or move it into the class definition. ═══ 19.776. EDC3375 ═══ The initializer must be enclosed in braces. Array element initializers must be enclosed in braces. Recovery: Ensure braces enclose the initializer. ═══ 19.777. EDC3376 ═══ union "&1" has multiple initializers associated with its constructor "&2". At most one of the union's member objects can be stored in at any time. Recovery: Remove all but one of the initializers. ═══ 19.778. EDC3377 ═══ "&1" is declared on line &2 of "&3". ═══ 19.779. EDC3378 ═══ "&1" is defined on line &2 of "&3". ═══ 19.780. EDC3379 ═══ Maximum number of error messages exceeded. Recovery: Begin correcting the errors. ═══ 19.781. EDC3380 ═══ Virtual function "&1" is not a valid override because "&3" is an ambiguous base class of "&2". The compiler must generate code to convert the actual return type into the type that the overridden function returns (so that calls to the original overridden function is supported). Unfortunately, the conversion is ambiguous. Recovery: Clarify the base class. ═══ 19.782. EDC3381 ═══ The operands have type "&1" and "&2". ═══ 19.783. EDC3382 ═══ "&1" is defined in this compilation and cannot be imported. Only externally defined functions can be imported. Recovery: Remove the directive that imports the function. ═══ 19.784. EDC3383 ═══ "&1" is not defined in this compilation and cannot be exported. Only functions defined in this compilation can be exported. Recovery: Remove the directive that exports the function. ═══ 19.785. EDC3384 ═══ "&1" is already imported or exported. Duplicate directive ignored. A function may be imported or exported at most once. Recovery: Remove one of the directives. ═══ 19.786. EDC3385 ═══ Macro "&1" has been invoked with an incomplete argument for parameter "&2". The terminating "," or ")" for the argument was not found. Recovery: Ensure the terminating "," or ")" is in the argument. ═══ 19.787. EDC3386 ═══ The enum cannot be packed to the requested size of &1. The enum type is too large to fit in the storage requested with the /Su option. Recovery: Redefine the storage to a larger size. ═══ 19.788. EDC3387 ═══ "&1" is not initialized until after the base class is initialized. First, the base classes are initialized in declaration order, then the members are initialized in declaration order, then the body of the constructor is executed. ═══ 19.789. EDC3388 ═══ The left hand side expression of the "&1" operator is a relational expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.790. EDC3389 ═══ The left hand side expression of the "&1" operator is a logical expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.791. EDC3390 ═══ The left hand side expression of the "&1" operator is an equality expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.792. EDC3391 ═══ The right hand side expression of the "&1" operator is a relational expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.793. EDC3392 ═══ The right hand side expression of the "&1" operator is a logical expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.794. EDC3393 ═══ The right hand side expression of the "&1" operator is an equality expression ("&2"). The "&3" operator may have been intended. Recovery: Ensure the proper operator is being used. ═══ 19.795. EDC3394 ═══ Assignment to the "this" pointer is not allowed. The "this" pointer is a const pointer. Recovery: Remove the assignment to the "this" pointer. ═══ 19.796. EDC3395 ═══ "&1" must not have any arguments. Recovery: Remove all arguments from the special member function. ═══ 19.797. EDC3396 ═══ The second operand to the "offsetof" operator is not valid. The second operand to the "offsetof" operator must consist only of "." operators and "[]" operators with constant bounds. Recovery: Remove or change the second operand. ═══ 19.798. EDC3397 ═══ "&1" is a member of "&2" and cannot be used without qualification. The specified name is a class member, but no class qualification has been used to reference it. Recovery: Use the scope operator (::) to qualify the name. ═══ 19.799. EDC3398 ═══ "&1" is undefined. Every variable of type "&2" will assume "&1" has no virtual bases and does not use multiple inheritance. The definition of the class is not given but the compiler must implement the pointer to member. It will do so by assuming the class has at most one nonvirtual base class. Recovery: If this assumption is incorrect, define the class before declaring the member pointer. ═══ 19.800. EDC3399 ═══ "&1" is undefined. The delete operator will not call a destructor. The definition of the class is not given so the compiler does not know whether the class has a destructor. No destructor call will be made. Recovery: Define the class. ═══ 19.801. EDC3400 ═══ Label "&1" is undefined. The specified label is being used but is not defined. Recovery: Define the label before using it. ═══ 19.802. EDC3401 ═══ The initializer for enumerator "&1" must be an integral constant expression. The value of an enumerator must be a constant expression that is promotable to a signed int value. Recovery: Change the initializer to an integral constant expression. A constant expression has a value that can be determined during compilation and does not change during program execution. ═══ 19.803. EDC3402 ═══ Static member template encountered - see Programming Guide for restrictions Templates for static data members are only partially supported, and may cause linker errors if they are overridden by explicit definitions, or if they occur in library objects. For more details, see the chapter on "Using Templates in C++ Programs" in the Programming Guide. Recovery: Ensure that you observe the restrictions listed in the Programming Guide. ═══ 19.804. EDC3403 ═══ Overriding virtual function "&1" may not return "&2" because class &3 has multiple base classes or a virtual base class. Contravariant virtual functions are supported only for classes with single inheritance and no virtual bases. Recovery: Ensure the class has single inheritance and no virtual bases. ═══ 19.805. EDC3404 ═══ Virtual function "&1" is not a valid override because "&3" is an inaccessible base class of "&2". The compiler must generate code to convert the actual return type into the type that the overridden function returns (so that calls to the original overridden function is supported). Unfortunately, the target type is inaccessible to the overriding function. Recovery: Make the base class accessible. ═══ 19.806. EDC3405 ═══ "&1" is a member of &2 classes. To reference one of these members the member must be qualified. Recovery: Use the scope operator (::) to qualify the name. ═══ 19.807. EDC3406 ═══ "&1" is a member of "&2". ═══ 19.808. EDC3407 ═══ "&1" is not the name of a function. A function name is required in this context. The specified name has been declared but it is not the name of a function. Recovery: Ensure the name is the correctly-spelled name of a function. ═══ 19.809. EDC3408 ═══ Priority value in "#pragma priority" is in system reserved range. #pragma priority values less than -2147482624 are reserved for system purposes. Recovery: Change the #pragma priority value so that it is greater than -2147482624. ═══ 19.810. EDC3409 ═══ Priority values in successive "#pragma priority" statements must increase. Recovery: Ensure priority values in successive "#pragma priority" statements increase. ═══ 19.811. EDC3410 ═══ Initialization or termination done before first "#pragma priority" statement. Recovery: Ensure initialization or termination follows the first "#pragma priority" statement. ═══ 19.812. EDC3417 ═══ Enum type "&1" cannot contain both negative and unsigned values. Recovery: Remove the negative or unsigned values. ═══ 19.813. EDC3418 ═══ A conflicting #pragma alloc_text was previously supplied for function &1. ═══ 19.814. EDC3419 ═══ Syntax error in directive - expected "&1" and found "&2". A syntax error was found during preprocessing. The message identifies what the compiler expected and what it actually found. Recovery: Correct the syntax error. ═══ 19.815. EDC3420 ═══ Ordinal value on #pragma import or export must be in range 0 to 65535. Recovery: Change the ordinal value so that it is within the range. ═══ 19.816. EDC3422 ═══ Functions callable from 16-bit code may not have by-value aggregate parameters. Recovery: Remove the by-value aggregate parameters. ═══ 19.817. EDC3423 ═══ Functions callable from 16-bit code may not return an aggregate by value. Recovery: Remove the return of an aggregate by value. ═══ 19.818. EDC3427 ═══ Address of the machine coded function "&1" can not be taken. ═══ 19.819. EDC3431 ═══ Invalid pragma name "&1" ignored. Recovery: Remove the invalid pragma name. ═══ 19.820. EDC3432 ═══ Illegal character "&1" found in macro name "&2". An illegal character is found in the macro specified Recovery: Remove the illegal character from the macro. ═══ 19.821. EDC3433 ═══ An initializer is not allowed for the nonvirtual function "&1". The declaration of a pure virtual function must include the keyword virtual. Recovery: Remove the initializer. ═══ 19.822. EDC3458 ═══ Template class matches more than one #pragma pack. Recovery: Ensure the template class matches only one #pragma pack. ═══ 19.823. EDC3474 ═══ Argument to va_start must be a parameter name. Recovery: Ensure argument to va_start is a parameter name. ═══ 19.824. EDC3475 ═══ A local variable or compiler temporary is being used to initialize reference member "&1". The local variable is only alive until the end of the function, but it is being used to initialize a member reference variable. Recovery: Ensure that no part of your program depends on the variable or temporary. ═══ 19.825. EDC3476 ═══ Compilation aborted by user or by the operating system. The user pressed Ctrl-C or the operating system killed the process. Possible cause: swap space is exhausted ═══ 19.826. EDC4004 ═══ Not enough memory is available. The compiler can not obtain the necessary virtual storage or memory. Recovery: Any of the following may help: o Shut down large processes. o Ensure your swap path is large enough. o Redefine your virtual disk, if you are using one. o Reboot. o Obtain more RAM and/or disk space. ═══ 19.827. EDC4005 ═══ Error occurred in an intermediate file. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.828. EDC4006 ═══ An addressing mode combination is not valid. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.829. EDC4008 ═══ An unsupported data type was encountered. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.830. EDC4010 ═══ An unexpected dependent register was encountered. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.831. EDC4011 ═══ Error occurred while opening assembly file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.832. EDC4012 ═══ Error occurred while writing assembly file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.833. EDC4013 ═══ Error occurred while closing assembly file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.834. EDC4014 ═══ Error occurred while opening object file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.835. EDC4015 ═══ Error occurred while in writing object file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.836. EDC4016 ═══ Error occurred while closing object file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The target directory of the assembler or object file is writable o These directories exist and have enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.837. EDC4017 ═══ Expression contains division by zero. The optimizer identified an expression containing division by zero. Recovery: Eliminate the division by zero if it was not intended. ═══ 19.838. EDC4018 ═══ Too many debug options were specified. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.839. EDC4019 ═══ Error occurred while opening intermediate file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The directory exists and has enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.840. EDC4020 ═══ Error occurred while writing to intermediate file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The directory exists and has enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.841. EDC4021 ═══ Error occurred while reading from intermediate file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The directory exists and has enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.842. EDC4022 ═══ Error occurred while closing intermediate file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The directory exists and has enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.843. EDC4023 ═══ Error occurred while creating name. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.844. EDC4024 ═══ Expression contains modulo by zero. The optimizer identified an expression containing modulo by zero. Recovery: Eliminate the modulo by zero if it was not intended. ═══ 19.845. EDC4026 ═══ Data definitions require more 16-bit segments than are allowed. The data declared requires more 16-bit segments than the maximum 242 available. Recovery: Break the program down into several smaller programs, or use less data. ═══ 19.846. EDC4027 ═══ The text associated with a #pragma comment user is too long. The text of the #pragma comment user directive exceeds the limit of 255 characters. Recovery: Shorten the text of the comment, or use multiple #pragma comment user directives. ═══ 19.847. EDC4028 ═══ The path or file name for output file &2 is not valid. The path or file name given has not been specified correctly. Recovery: Check the spelling and syntax of the path or file name and change the name accordingly. ═══ 19.848. EDC4029 ═══ Open access denied for output file &2. The file system will not allow the specified file to be opened. You may be trying to write to a readonly disk. Recovery: Direct output to a writable disk. ═══ 19.849. EDC4030 ═══ Cannot open output file &2. An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC4014. ═══ 19.850. EDC4031 ═══ Cannot open output file &2. The file is already open. Another process has already opened the file. Recovery: Close the file and compile again. ═══ 19.851. EDC4032 ═══ Cannot write to the output file. The disk is full. Recovery: Delete some files to make some space on the disk. ═══ 19.852. EDC4033 ═══ Precondition violated. An internal compiler error has occurred. Recovery: See your IBM Service Representative. ═══ 19.853. EDC4034 ═══ The command line passed to the Back End is not correct. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.854. EDC4035 ═══ Error occurred while opening source file. An operating system or compiler error has occurred. Recovery: Ensure that: o No other processes are modifying the directory or file o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.855. EDC4036 ═══ The path or file name for source file &2 is not valid. The path or file name given has not been specified correctly. Recovery: Check the spelling and syntax of the path or file name and change the name accordingly. ═══ 19.856. EDC4037 ═══ Open access denied for source file &2. The file system will not allow the specified file to be opened. because of an OS/2 file system error. Recovery: Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.857. EDC4038 ═══ Cannot open source file &2. An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC4035. ═══ 19.858. EDC4039 ═══ Cannot open source file &2. The file is already open. Another process has already opened the file. Recovery: Close the file and compile again. ═══ 19.859. EDC4040 ═══ Assembler listing line is too long for successful assembly. The line in the assembler listing is too long to be assembled. Recovery: Try using shorter variable and function names. ═══ 19.860. EDC4041 ═══ Error occurred while closing source file. An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC4035. ═══ 19.861. EDC4042 ═══ Cannot use __parmdwords in a non SYSTEM linkage function. The __parmdwords function can only be called from a function that uses _System linkage. Recovery: Change the linkage type of the function using the /Ms compiler option or the _System keyword, or remove the call to __parmdwords. ═══ 19.862. EDC4043 ═══ Automatic function inliner will inline function &2. The /Oi+ option controls the inlining of user functions. When selected, all functions qualified by _Inline or inline become the default. Recovery: Informative message only. ═══ 19.863. EDC6004 ═══ Not enough memory available. The compiler can not obtain the necessary virtual storage or memory. Recovery: Any of the following may help: o Shut down large processes. o Ensure your swap path is large enough. o Redefine your virtual disk, if you are using one. o Reboot. o Obtain more RAM and/or disk space. ═══ 19.864. EDC6005 ═══ Error occurred in intermediate file. An internal compiler error has occurred. Recovery: Contact your IBM Service Representative. ═══ 19.865. EDC6006 ═══ A type mismatch was found between declarations of symbol &2 in files &3 and &4. At least one different symbol was found in the source files for a common identifier. All symbols for identifiers must match. Recovery: Change the code so that all common identifiers have matching symbols, and recompile. ═══ 19.866. EDC6007 ═══ An illegal redefinition of symbol &2 defined in file &3 occurred in file &4. At least one different symbol definition was found in the source files. All common symbol definitions must match. Recovery: Remove the redefinition so that all symbols have identical definitions, and recompile. ═══ 19.867. EDC6008 ═══ The value of the /R option must be consistent across source files. Some source files were compiled with different /R options. Only one option must be specified, either the /Re (runtime library) option or the /Rn (subsystem library). Recovery: Change the code so all files have the same /R option, and recompile. ═══ 19.868. EDC6009 ═══ The value of the /G3, /G4, /G5 options must be consistent across source files. The source files were compiled for different target processors. All source files specified at one time must point to the same processor. Recovery: Change the code so all files point to the same processor, and recompile. ═══ 19.869. EDC6010 ═══ The value of the &2 option must be consistent across source files. The source files were compiled with different versions of the option specified. They must all use the same version of the option. Recovery: Change the code so all the files specify the same version of the option, and recompile. ═══ 19.870. EDC6011 ═══ The value of the /O option must be consistent across source files. Some source files were compiled with different /O options. Only one option must be specified in all source files. Recovery: Change the code so that the source files have the same option, and recompile. ═══ 19.871. EDC6012 ═══ A second #pragma entry was detected in file &2. #pragma entry sets the entry point for the application, and there can never be more than one entry point to an application. Recovery: Remove the second #pragma entry from the file, and recompile. ═══ 19.872. EDC6013 ═══ The declarations of functions &2 in file &3 and file &4 have inconsistent linkages. The function declarations are not consistent from file to file. Recovery: Change the code so that all the source files have the exact same function declarations, and recompile. ═══ 19.873. EDC6014 ═══ The declarations of functions &2 in file &3 and file &4 have inconsistent numbers of parameters. The function declarations are not consistent from file to file. Recovery: Change the code so that all the source files have the exact same function declarations, and recompile. ═══ 19.874. EDC6015 ═══ The declarations of functions &2 in file &3 and file &4 have inconsistent variable argument properties. The function declarations are not consistent from file to file. Recovery: Change the code so that all the source files have the exact same function declarations, and recompile. ═══ 19.875. EDC6016 ═══ The command line passed to the Intermediate Code Linker is not correct. An internal compiler error has occurred. Recovery: Contact your local IBM Service Representative. ═══ 19.876. EDC6017 ═══ Unknown error. An error has occurred which is beyond the recognition of the compiler. Recovery: Contact your local IBM Service Representative. ═══ 19.877. EDC6018 ═══ Error in .def file &1. While the intermediate linker was parsing the .def file an error was found. Recovery: Check the .def file and correct the error. ═══ 19.878. EDC6019 ═══ Error occurred while opening intermediate file. An operating system or compiler error has occurred. Recovery: Ensure that: o The TMP directory is set to a writable disk o The directory exists and has enough available space o No other processes are modifying the directory or file o The file system is functioning properly o The virtual disk for the directory, if you are using one, is large enough. Try rebooting. If the problem persists, contact your IBM Service Representative. ═══ 19.879. EDC6020 ═══ Error occurred while writing to the intermediate file. An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC6019. ═══ 19.880. EDC6021 ═══ Error occurred while reading from the intermediate file. An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC6019. ═══ 19.881. EDC6022 ═══ An operating system or compiler error has occurred. Recovery: See the Recovery for message EDC6019. ═══ 19.882. EDC6023 ═══ Error occurred while creating name. An internal compiler error has occurred. Recovery: Contact your local IBM Service Representative. ═══ 19.883. EDC6024 ═══ Source files containing conflicting debug language indicators were linked, debugging may be restricted. The debug language environment was set to handle the language of the last file processed. If that language was not C++, then debugging of the program will be restricted. p.Recovery: ═══ 20. Runtime Messages and Return Codes ═══ This section contains information about the runtime messages and should not be used as programming interface information. The value of the return code from a runtime error is set in one of the following ways: o By the initialization or termination routines of the C/C++ Tools runtime library or by the program management routines o By the return statement in your main program o By calling the exit, _exit, or abort functions from your C program. o By calling the DosExit API. It is possible to pass a return code from a C or C++ program to the program that invoked it. For example, if the program is invoked by the operating system, a return code can be passed either for examination in a subsequent program, if running of that program is conditional upon the value of the code returned, or merely to indicate conditions that were encountered during running. The return code generated by a C/C++ Tools program can be expected to be within the valid range of the int type. The range of values may be smaller if the return code is checked inside a batch .CMD file. See the OS/2 2.0 documentation for the acceptable range of return codes. Unless an error is detected that prevents the program management functions of the C/C++ Tools from operating correctly, the return code is always returned to the caller of the program. If your program did not specify a value for the return code either by an explicit return statement or by an exit statement, the return value is undefined. Related Information o Runtime Messages o return o abort - Stop a Program o exit - End Program o _exit - End Program ═══ 20.1. Runtime Messages ═══ These are messages you see while your C/C++ Tools program is running. Runtime messages are produced in one of three ways: o Through a call to the perror or strerror function o In a machine-state dump when the exception handler terminates a program o Through a call to a debug memory management function. In extreme circumstances, when a runtime library function fails, an INTERNAL LIBRARY ERROR message is displayed along with the name of the library function that has failed. Make sure you have correctly installed the compiler. If the problem persists, contact your IBM service representative. The panels following this one list the error messages associated with errno values, in the format shown below. You can use the perror and strerror library functions to print these messages. The errno value does not prefix the message. Not all error messages are associated with an errno value. Note: While the integer value of errno is not to be used as programming interface information, you can use the macro values defined in as a programming interface. Message Format: EDCnnnn : text where: nnnn - error message number text - message text, which may contain substitution text indicated by &n Related Information o perror - Print Error Message o strerror - Set Pointer to Runtime Error Message o errno.h o Runtime Messages and Return Codes ═══ 20.2. EDC5000 ═══ Errno is 0. No error occurred. ═══ 20.3. EDC5001 ═══ Domain error. errno Value: EDOM A parameter used is beyond the allowable domain of the function. Recovery: Check the domain of the function and change the parameter. ═══ 20.4. EDC5002 ═══ Range error. errno Value: ERANGE The value computed is outside the allowable range of the function. Recovery: Check the range of the function and ensure your values work within it. ═══ 20.5. EDC5003 ═══ The mode type parameter is not correct. errno Value: EBADMODE Recovery: Change the parameter to a valid mode type. ═══ 20.6. EDC5004 ═══ The file name is "", a null pointer, or an invalid DDNAME. errno Value: EBADNAME The file name or DDNAME was not specified correctly. Recovery: Use the correct file name or DDNAME. ═══ 20.7. EDC5005 ═══ Temporary memory files cannot be reopened. errno Value: EISTEMPMEM Recovery: Use a normal memory file or a temporary disk file. ═══ 20.8. EDC5006 ═══ The file sharing mode specified is not correct. errno Value: EBADSHARE Valid sharing modes are NONE, ALL, and READ. Recovery: Specify a valid sharing mode. ═══ 20.9. EDC5007 ═══ The buffering mode specified is not correct. errno Value: EBUFMODE The buffer mode was not correct. Valid buffering modes are IOLBF, IOFBF, and IONBF. Recovery: Specify a valid buffering mode. ═══ 20.10. EDC5008 ═══ A previous error occurred on the stream. errno Value: EERRSET A previous fatal error occurred on the stream and this is the first opportunity to report it. Recovery: Close the stream and retry the operation. ═══ 20.11. EDC5009 ═══ The file is open. errno Value: EISOPEN The operation is not permitted on the file because a process has the file open in an incorrect sharing mode. Recovery: Close the file and retry the operation, or ensure the sharing modes are consistent. ═══ 20.12. EDC5010 ═══ The file cannot be found. errno Value: ENOTEXIST The file specified cannot be found. Either the file name was not correctly specified, or the file has not been created. Recovery: Ensure the file name is correctly specified or create the file. ═══ 20.13. EDC5011 ═══ This operation must be done before any reads, writes or repositions. errno Value: ENOTINIT Recovery: Correct the program logic. ═══ 20.14. EDC5012 ═══ The stream pointer is NULL. errno Value: ENULLFCB The stream pointer must point to a valid stream. Recovery: Ensure the stream pointer points to a valid stream, and reopen the stream. ═══ 20.15. EDC5013 ═══ Not enough memory is available to complete the operation. errno Value: EOUTOFMEM Recovery: Ensure that memory is being freed when it is no longer used, and that memory swapping is allowed. Use the _heapmin function to release unused memory from the heap. Stop large programs from running while the current application is being run. ═══ 20.16. EDC5014 ═══ The specified buffer size is too small. errno Value: ESMALLBF Recovery: Specify a larger buffer for the file. ═══ 20.17. EDC5016 ═══ The file already exists. errno Value: EEXIST An attempt was made to rename a file to an already existing file name. Recovery: Change the name of the existing file or of the new file. ═══ 20.18. EDC5017 ═══ A unique file name cannot be generated. errno Value: ENOGEN A call to tmpnam or _tempnam failed because all unique file names have been used. Recovery: Close at least one temporary file. ═══ 20.19. EDC5019 ═══ The seek operation is not valid for this stream. errno Value: ENOSEEK The stream is connected to a device that does not permit the seek operation. Recovery: Remove the seek operation or point the stream to a different device. ═══ 20.20. EDC5020 ═══ The file position for the file is not valid. errno Value: EBADPOS The file position is not valid for a file positioning function. Recovery: Rewind the file or call fflush to clear any characters. Put the file back in the stream, and retry the operation. ═══ 20.21. EDC5022 ═══ Attempted to seek to an invalid file position. errno Value: EBADSEEK The combination of starting point and offset values specified for the fseek function is not valid for the file, or an attempt was made to seek beyond the beginning of a binary or text file. Recovery: Ensure the values specified for fseek are valid. ═══ 20.22. EDC5023 ═══ The file or directory specified cannot be found. errno Value: ENOENT Recovery: Ensure the path name and file name are specified correctly. Create the file or directory if necessary. ═══ 20.23. EDC5024 ═══ The file or directory specified is read-only. errno Value: EACCESS The path name specifies a file or directory that cannot be written to. Recovery: Change the file name if necessary or remove the read-only attribute from the file or directory. ═══ 20.24. EDC5025 ═══ Too many open files. errno Value: EMFILE Because too many files are open, the specified file cannot be opened to change its modification time. Recovery: Close some files. ═══ 20.25. EDC5026 ═══ A command processor could not be found. errno Value: ENOCMD The command processor specified by the COMSPEC environment variable cannot be found, and CMD.EXE cannot be found in any of the directories specified by the PATH environment variable. Recovery: Ensure that the COMSPEC variable specifies a valid path and file name for the command processor, and/or that CMD.EXE exists in one of the directories specified by PATH. ═══ 20.26. EDC5028 ═══ A read operation cannot immediately follow a write operation. errno Value: EGETANDPUT Recovery: Flush the stream or use one of the repositioning functions before doing a read operation. ═══ 20.27. EDC5029 ═══ Attempted to read past end-of-file. errno Value: EPASTEOF Recovery: Reposition the file before reading. ═══ 20.28. EDC5030 ═══ The file is not open for reading. errno Value: ENOTREAD Recovery: Close the file and reopen it in a mode that permits reading. ═══ 20.29. EDC5031 ═══ Too many consecutive calls to ungetc. errno Value: ETOOMANYUNGETC The ungetc function is not guaranteed to work for consecutive calls. Recovery: Read the last ungetc character, or use one of the repositioning functions to clear the buffer. ═══ 20.30. EDC5032 ═══ Cannot put EOF back to the stream. errno Value: EUNGETEOF The EOF character is not a valid parameter to ungetc or ungetch Recovery: Eliminate the ungetc or ungetch operation. ═══ 20.31. EDC5033 ═══ Cannot put a character back to the stream immediately following a write operation on the stream. errno Value: EPUTUNGET The ungetc or ungetch function cannot be used immediately following a write operation. Recovery: Flush the stream or use one of the repositioning functions before using the unget operation. ═══ 20.32. EDC5034 ═══ The process identifier specified for the child process is not valid. errno Value: ECHILD The child process does not exist, or the process identifier is not correct. Recovery: Make sure that the process identifier for the child process to be waited on is correct. ═══ 20.33. EDC5035 ═══ The child process ended abnormally. errno Value: EINTR A trap, an unintercepted DosKill call or exception, or a hardware error occurred. Recovery: Check the code in the child process. ═══ 20.34. EDC5036 ═══ The action code specified is not correct. errno Value: EINVAL Valid action codes for _cwait are WAIT_CHILD and WAIT_GRANDCHILD. Recovery: Specify a valid action code. ═══ 20.35. EDC5037 ═══ Cannot run the specified file. errno Value: ENOEXEC The executable format of the file is not valid, or the file is not an executable file. Recovery: Ensure the file specified is a valid excutable file. ═══ 20.36. EDC5038 ═══ Cannot start another process. errno Value: EAGAIN Another process cannot be created because it will exceed the maximum number of processes allowed by OS/2. Recovery: Close some of the other processes running. ═══ 20.37. EDC5039 ═══ The stream specified is the wrong type for the operation. errno Value: EBADTYPE Recovery: Use the correct type of stream for the operation required. ═══ 20.38. EDC5040 ═══ The file is not opened for writing. errno Value: ENOTWRITE The file may be opened in read mode. Recovery: Reopen the file with a file mode that allows the write operation. ═══ 20.39. EDC5041 ═══ A write operation must not immediately follow a read operation. errno Value: EPUTANDGET Recovery: Flush the stream or use one of the repositioning functions before doing the write operation. ═══ 20.40. EDC5042 ═══ The specified buffer length is too large. errno Value: ELARGEBF The size of the buffer must be in the range of a long int. Recovery: Specify a smaller buffer size. ═══ 20.41. EDC5043 ═══ The file handle is not valid. errno Value: EBADF The file handle passed to _fstat must be recognized by the OS/2 system. Recovery: Specify a valid file handle. ═══ 20.42. EDC5044 ═══ Cannot rename a file to a different device. errno Value: EXDEV A file cannot be renamed to a different drive or device. Recovery:Rename the file to a different name or copy the file to the new device and then rename it. ═══ 20.43. EDC5045 ═══ There is no space left on the device. errno Value: ENOSPC There is not enough free space on the device to complete the requested operation. Recovery: Remove any files that are not needed from the device and try the operation again. ═══ 20.44. EDC5046 ═══ An unrecognized exception occurred in a math routine. The control word has probably been changed. errno Value: EMATH ═══ 20.45. EDC5047 ═══ The DLL specified cannot be found. errno Value: EMODNAME The DLL may not exist, or may not be specified in the LIBPATH environment variable. Recovery: Ensure the name is correct and is specified in the LIBPATH variable. ═══ 20.46. EDC5049 ═══ The value specified for blksize or lrecl is too large. errno Value: EMAXATTR See fopen for the range of valid values for blksize and lrecl. Recovery: Specify valid values for blksize and lrecl. ═══ 20.47. EDC5050 ═══ Error in reading the C Locale Description (CLD) file. errno Value: EREADERROR The CLD file specified in your DPATH variable may be damaged or have an incorrect format. Recovery: Ensure the DPATH variable points to a valid .CLD file. If the file is damaged, reinstall it. ═══ 20.48. EDC5051 ═══ The value specified for blksize or lrecl conflicts with a previously set value. errno Value: EBADATTR The values for blksize and lrecl may have been set by both a ddname and by fopen. Recovery: Ensure the values for blksize and lrecl are consistent. ═══ 20.49. EDC5060 ═══ OS/2 returned error code &1. errno Value: EOS2ERR An operating system call returned the error code given. Recovery: Refer to the OS/2 documentation under the error code given. ═══ 20.50. EDC5090 ═══ Complex: log: singularity: log((0,0)). An attempt was made to use the complex 0 in the log function, which is undefined. Recovery: Do not try to use the complex 0 with the log function. ═══ 20.51. EDC5091 ═══ Iostream: Error in form(): too many characters. The form function is used only for compatibility with earlier versions of the I/O Stream Library. It is not intended for use with new C++ code. As a result internal conversion buffer has been overwritten. Recovery: Reduce the number of conversion specifiers to be passed on to form. ═══ 20.52. EDC5098 ═══ The floating-point conversion code is not linked in. An attempt was made to print a non-floating-point variable using a floating-point format specifier. Recovery: Ensure the correct format specifier is used for the type of variable to be printed. ═══ 20.53. EDC5099 ═══ Internal library error in function: &1, line: &2. An internal library error has occurred. Recovery: Contact your IBM Service Representative. ═══ 20.54. EDC5100 ═══ Not enough storage is available to complete initialization. Recovery: Stop large programs from running while the current application is being run. ═══ 20.55. EDC5101 ═══ Assertion failed: &1, file: &2, line: &3. This is the message generated by the assert macro. Recovery: Correct the error that caused the assertion to fail. ═══ 20.56. Exception Messages ═══ EDC5101 to EDC5145 are generated when an unhandled or incorrectly handled exception occurs, and are displayed in the resulting machine-state dump. Exceptions are explained in more detail in the OS/2 documentation. For more information on these messages, see the section on exception handling in the Programming Guide. ═══ 20.57. EDC5102 ═══ Integer Division by Zero exception occurred at EIP = &1 on thread &2. An Integer Division by Zero exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.58. EDC5103 ═══ Invalid Opcode exception occurred at EIP = &1 on thread &2. An Invalid Opcode exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.59. EDC5104 ═══ General Protection Fault exception occurred at EIP = &1 on thread &2. A General Protection Fault exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.60. EDC5106 ═══ Guard Page Allocation Failure exception occurred at EIP = &1 on thread &2. The compiler has run out of stack space. Recovery: Allocate more stack space and recompile. ═══ 20.61. EDC5110 ═══ Overflow exception occurred at EIP = &1 on thread &2. An Overflow exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.62. EDC5111 ═══ Bound exception occurred at EIP = &1 on thread &2. A Bound exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.63. EDC5112 ═══ Exception number 0x&2 occurred at EIP = &1 on thread &2. The exception identified by the number given occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.64. EDC5113 ═══ Exception was marked as non-continuable. The operating system will not allow the exception to be continued. This is an informational message that may accompany an initial exception message. ═══ 20.65. EDC5114 ═══ Exception occurred handling a prior exception. The exception occurred inside the exception handler. This is an informational message that may accompany an initial exception message. ═══ 20.66. EDC5115 ═══ Process terminating. Confirmational message generated by the exception handler. This is an informational message that may accompany an initial exception message. ═══ 20.67. EDC5116 ═══ Register dump at point of exception: This message indicates a machine-dump was performed. The machine state follows and may consist of any combination of the messages EDC5117-EDC0121 and EDC5124-EDC0130. ═══ 20.68. EDC5117 ═══ EAX = &1 EBX = &2 ECX = &3 EDX = &4 These are the values of the registers at the time of the exception. ═══ 20.69. EDC5118 ═══ EBP = &1 EDI = &2 ESI = &3 ESP = &4 These are the values of the registers at the time of the exception. ═══ 20.70. EDC5119 ═══ CS = &1 CSLIM = &2 DS = &3 DSLIM = &4 These are the values of the registers at the time of the exception. ═══ 20.71. EDC5120 ═══ ES = &1 ESLIM = &2 FS = &3 FSLIM = &4 These are the values of the registers at the time of the exception. ═══ 20.72. EDC5121 ═══ GS = &1 GSLIM = &2 SS = &3 SSLIM = &4 These are the values of the registers at the time of the exception. ═══ 20.73. EDC5122 ═══ Failed to register exception handler. A severe operating system error has occurred. Recovery: Contact your IBM Service Representative ═══ 20.74. EDC5123 ═══ Invalid buffer passed to longjmp(). The buffer passed to the longjmp function is not valid. Recovery: Correct the code and recompile. ═══ 20.75. EDC5124 ═══ NPX Environment: This is the state of the NPX at the time the exception occurred. It may be accompanied by any combination of the messages EDC5125-EDC0130. ═══ 20.76. EDC5125 ═══ CW = &1 TW = &2 IP = &4:&3 These are the values of the control word, tag word, and instruction pointer in the NPX at the time the exception occurred. ═══ 20.77. EDC5126 ═══ SW = &1 OPCODE = &2 OP = &4:&3 These are the values of the status word, opcode, and the operand address in the NPX at the time the exception occurred. ═══ 20.78. EDC5127 ═══ NPX Stack: This is the state of the NPX stack at the time the exception occurred. ═══ 20.79. EDC5128 ═══ ST(&1): exponent = &3 significand = &2 &4 &5 One copy of this message appears for each valid stack entry in the NPX. ═══ 20.80. EDC5129 ═══ Exception occurred in C library routine called from EIP = &1. The exception occurred within a C library function. In this case, the EIP given is the instruction pointer in the user program where the call to the function occurred. This is an informational message that may accompany an initial exception message. ═══ 20.81. EDC5130 ═══ No valid stack entries. There is no valid data in the NPX stack. ═══ 20.82. EDC5131 ═══ Privileged Opcode exception occurred at EIP = &1 on thread &2. A Privileged Opcode exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.83. EDC5132 ═══ Data Misalignment Exception occurred at EIP = &1 on thread &2. A Data Misalignment Exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.84. EDC5133 ═══ Floating Point Denormal Operand exception occurred at EIP = &1 on thread &2. A Floating Point Denormal Operand exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.85. EDC5134 ═══ Floating Point Divide by Zero exception occurred at EIP = &1 on thread &2. A Floating Point Division by Zero exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.86. EDC5135 ═══ Floating Point Precision exception occurred at EIP = &1 on thread &2. A Floating Point Precision exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.87. EDC5136 ═══ Floating Point Invalid Operation exception occurred at EIP = &1 on thread &2. A Floating Point Invalid Operation exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.88. EDC5137 ═══ Floating Point Overflow exception occurred at EIP = &1 on thread &2. A Floating Point Overflow exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.89. EDC5138 ═══ Floating Point Stack Check exception occurred at EIP = &1 on thread &2. A Floating Point Stack Check exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.90. EDC5139 ═══ Floating Point Underflow exception occurred at EIP = &1 on thread &2. A Floating Point Underflow exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.91. EDC5140 ═══ In Page exception occurred at EIP = &1 on thread &2. An In Page exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.92. EDC5141 ═══ Attempt to continue unrecoverable exception occurred at EIP = &1 on thread &2. The exception handler tried to continue an exception that the operating system considered noncontinuable at the location indicated. Recovery: Correct the code and recompile. ═══ 20.93. EDC5142 ═══ Invalid Disposition exception occurred at EIP = &1 on thread &2. An Invalid Disposition exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.94. EDC5143 ═══ Invalid Lock Sequence exception occurred at EIP = &1 on thread &2. An Invalid Lock Sequence exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.95. EDC5144 ═══ Bad Stack exception occurred at EIP = &1 on thread &2. A Bad Stack exception occurred at the location indicated. Recovery: Correct the code and recompile. ═══ 20.96. EDC5145 ═══ Invalid Unwind Target exception occurred at EIP = &1 on thread &2. An Invalid Unwind Target exception occurred at the location indicated. A possible cause is that the jmp_buf buffer supplied to the longjmp function was not valid. Recovery: Correct the code and recompile. ═══ 20.97. EDC5146 ═══ Invalid attempt to access storage location &1. This message accompanies an exception message and gives the address of the storage location that caused the exception to occur. ═══ 20.98. EDC5147 ═══ Exception = &1 occurred at EIP = &2. The exception identified by the number given occured at the location indicated. Recovery: Correct the code and recompile. ═══ 20.99. EDC5150 ═══ An internal data structure starting at address &1 was overwritten. An internal data structure that is allocated from a separate page of memory has been overwritten. Recovery: Correct the code so you do not overwrite the structure and recompile. ═══ 20.100. EDC5151 ═══ The invalid memory block address &1 was passed in at line &3 of &2. The free or realloc function was passed a pointer that did not point to a memory block allocated by malloc, calloc, or realloc. Recovery: Allocate the memory block with malloc, calloc, or realloc before passing the pointer to free or realloc. ═══ 20.101. EDC5152 ═══ Memory was overwritten before the allocated memory block which starts at address &1. Memory immediately before an allocated memory block has been overwritten. This message is accompanied by the first eight bytes of the memory block and the file name and line number where the memory block was allocated, if available. Recovery: Correct the code and recompile. ═══ 20.102. EDC5153 ═══ The file name and line number are not available. The file name and line number where the memory block was allocated or freed are not available because too much memory was overwritten. This message accompanies other debug memory management messages. ═══ 20.103. EDC5154 ═══ Memory was overwitten after the allocated memory block which starts at address &1. Memory immediately after an allocated memory block has been overwritten. This message is accompanied by the first eight bytes of the memory block and the file name and line number where the memory block was allocated, if available. Recovery: Correct the code and recompile. ═══ 20.104. EDC5155 ═══ This memory block was freed at line number &1 in &2. This message accompanies messages about overwriting a free memory block. It indicates the file name and line number where the block was freed. ═══ 20.105. EDC5156 ═══ The first eight bytes of the memory block (in hex) are: &1. The first eight bytes of the memory block are given to help you determine what the block is or was used for. This message accompanies other debug memory management messages. ═══ 20.106. EDC5157 ═══ The free memory block which starts at address &1 has been accessed. An attempt was made to access the memory block at the address given, when the block had already been freed. Recovery: Correct the code to allocate the memory location, or do not free the memory block before you access it. ═══ 20.107. EDC5158 ═══ Memory was overwritten before the free memory block which starts at address &1. Memory immediately before a freed memory block has been overwritten. This message is accompanied by the first eight bytes of the memory block, and the file name and line number where the memory block was freed, if available. Recovery: Correct the code and recompile. ═══ 20.108. EDC5159 ═══ Memory was overwritten at the end of the free memory block which starts at address &1. Memory immediately after a freed memory block has been overwritten. This message is accompanied by the first eight bytes of the memory block, and the file name and line number where the memory block was freed, if available. Recovery: Correct the code and recompile. ═══ 20.109. EDC5160 ═══ Could not allocate memory for internal data structures. There is not enough memory available. Recovery: Ensure that memory is being freed when it is no longer used, and that memory swapping is allowed. Use the _heapmin function to release unused memory from the heap. Stop large programs from running while the current application is being run. ═══ 20.110. EDC5161 ═══ Could not register exception handler for memory access violations. A severe operating system error has occurred. Recovery: Contact your IBM Service Representative. ═══ 20.111. EDC5163 ═══ START OF DUMP OF ALLOCATED MEMORY BLOCKS This message indicates the start of the information produced by the _dump_allocated function. ═══ 20.112. EDC5164 ═══ END OF DUMP OF ALLOCATED MEMORY BLOCKS This message indicates the start of the information produced by the _dump_allocated function. ═══ 20.113. EDC5165 ═══ Address: &1 Size: &2 (&3) This message is produced by the _dump_allocated function. It gives the address and size of the allocated memory blocks. Recovery: ═══ 20.114. EDC5166 ═══ This memory block was (re)allocated at line number &1 in &2. This message accompanies messages about overwriting memory immediately before or after an allocated memory block. It indicates the file name and line number where the memory block was allocated or reallocated. ═══ 20.115. EDC5167 ═══ Memory contents: This message is produced by the _dump_allocated function. It gives the contents of the allocated memory blocks.