C CPP Reference Manual
C CPP Reference Manual
C/C++
Language Reference
SC09-2360-05
OS/390
C/C++
Language Reference
SC09-2360-05
Note!
Before using this information and the product it supports, be sure to read the information in Notices on page 411.
Contents
Part 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Chapter 1. About This Book . . . . . . .
Who Should Use This Book . . . . . . .
A Note about Examples . . . . . . . . .
IBM OS/390 C/C++ and Related Publications .
Hardcopy Books . . . . . . . . . . . .
PDF Books . . . . . . . . . . . . . .
Softcopy Books . . . . . . . . . . . .
Softcopy Examples . . . . . . . . . . .
OS/390 C/C++ on the World Wide Web . . .
How to Read the Syntax Diagrams . . . .
|
|
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 3
. 3
. 3
. 4
. 8
. 8
. 9
. 9
. . . . . . . . . . . . . 10
. . . . . . . . . . . . . 10
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
15
15
15
15
17
17
18
18
19
19
20
20
21
22
24
24
24
25
25
26
26
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
33
33
34
34
35
35
36
36
37
37
37
iii
iv
File Scope . . . . . . . . . . . . . . . .
Function Prototype Scope . . . . . . . . . . .
Example of Scope in C . . . . . . . . . . . .
Related Information . . . . . . . . . . . . .
Program Linkage . . . . . . . . . . . . . . .
Internal Linkage . . . . . . . . . . . . . .
External Linkage . . . . . . . . . . . . . .
No Linkage . . . . . . . . . . . . . . . .
Storage Duration . . . . . . . . . . . . . . .
Name Spaces . . . . . . . . . . . . . . . .
Related Information . . . . . . . . . . . . .
Command-Line Arguments . . . . . . . . . . .
Under OS/390 Batch . . . . . . . . . . . . .
Under IMS . . . . . . . . . . . . . . . .
Under CICS . . . . . . . . . . . . . . . .
Under TSO Command . . . . . . . . . . . .
Under TSO Call . . . . . . . . . . . . . .
Under OS/390 UNIX Shell . . . . . . . . . . .
Related Information . . . . . . . . . . . . .
Overview of the C++ Language . . . . . . . . . .
C++ Support for Object-Oriented Programming . . . .
Data Abstraction . . . . . . . . . . . . . .
Encapsulation . . . . . . . . . . . . . . .
Inheritance . . . . . . . . . . . . . . . .
Dynamic Binding and Polymorphism . . . . . . .
Other Features of C++ . . . . . . . . . . . .
C++ Programs . . . . . . . . . . . . . . . .
CBC3X02D . . . . . . . . . . . . . . . .
Scope in C++ . . . . . . . . . . . . . . . .
Local Scope . . . . . . . . . . . . . . . .
Function Scope. . . . . . . . . . . . . . .
File Scope . . . . . . . . . . . . . . . .
Class Scope . . . . . . . . . . . . . . . .
Simple C++ Input and Output . . . . . . . . . .
CBC3X02F . . . . . . . . . . . . . . . .
Output (cout, cerr, and clog) . . . . . . . . . .
Input (cin) . . . . . . . . . . . . . . . . .
Linkage Specifications Linking to non-C++ Programs .
CBC3X02J . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
37
37
37
38
38
39
39
40
40
40
41
41
41
42
42
42
42
42
43
43
43
43
44
44
44
45
45
47
47
47
48
48
48
48
49
49
50
50
51
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
53
53
53
54
55
56
56
58
58
58
59
59
59
60
60
61
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Integer Constants . . . . .
Floating-Point Constants . .
Fixed-Point Decimal Constants
Character Constants . . . .
String Literals . . . . . .
Escape Sequences . . . .
. . . .
. . . .
(C Only)
. . . .
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Chapter 5. Declarations . . . . . . . .
Declarations Overview . . . . . . . . .
Block Scope Data Declarations . . . . . .
Initialization . . . . . . . . . . . .
Storage . . . . . . . . . . . . .
Related Information . . . . . . . . .
File Scope Data Declarations . . . . . .
Initialization . . . . . . . . . . . .
Storage . . . . . . . . . . . . .
Related Information . . . . . . . . .
Objects. . . . . . . . . . . . . . .
Storage Class Specifiers . . . . . . . .
auto Storage Class Specifier . . . . . .
extern Storage Class Specifier . . . . .
register Storage Class Specifier. . . . .
static Storage Class Specifier . . . . .
typedef . . . . . . . . . . . . . . .
Examples of typedef Declarations . . . .
Related Information . . . . . . . . .
Type Specifiers . . . . . . . . . . . .
Characters . . . . . . . . . . . .
Floating-Point Variables. . . . . . . .
Fixed-Point Decimal Data Types (C Only) .
Integer Variables . . . . . . . . . .
Enumerations . . . . . . . . . . .
Pointers . . . . . . . . . . . . .
void Type . . . . . . . . . . . .
Arrays. . . . . . . . . . . . . .
Structures . . . . . . . . . . . .
Unions . . . . . . . . . . . . .
Declarators . . . . . . . . . . . .
Initializers . . . . . . . . . . . .
C/C++ Data Mapping . . . . . . . .
C++ Function Specifiers . . . . . . .
C++ References . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 71
. 71
. 72
. 73
. 73
. 73
. 73
. 74
. 74
. 74
. 74
. 74
. 75
. 77
. 83
. 83
. 85
. 86
. 86
. 87
. 87
. 88
. 89
. 90
. 91
. 95
. 100
. 101
. 107
. 114
. 121
. 129
. 131
. 131
. 131
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Contents
62
63
65
65
66
68
133
133
135
135
136
136
136
137
137
138
138
139
140
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
141
142
142
142
143
143
144
144
144
144
145
145
146
146
148
148
151
152
152
153
153
153
154
154
154
155
156
157
158
158
159
160
160
161
162
162
162
163
163
164
165
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
167
167
167
168
168
168
168
169
169
169
170
170
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
vi
Functions Overview. . . . . . . . .
C++ Enhancements to C Functions . . .
Function Declarations . . . . . . . .
C Function Declarations . . . . . .
C++ Function Declarations . . . . .
Examples of Function Declarations . .
Function Definitions. . . . . . . .
Related Information . . . . . . . .
The main() Function . . . . . . . .
Arguments to main . . . . . . . .
Example of Arguments to main . . .
Calling Functions and Passing Arguments
Passing Arguments in C++ . . . . .
Examples of Calling Functions. . . .
Passing Arguments by Reference . .
Default Arguments in C++ Functions . .
CBC3X06B . . . . . . . . . . .
Restrictions on Default Arguments . .
Evaluating Default Arguments . . . .
Function Return Values . . . . . . .
Using References as Return Types . .
Pointers to Functions . . . . . . . .
C++ Inline Functions . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
173
173
174
174
174
176
178
183
183
183
184
184
186
186
188
189
189
190
190
191
192
192
194
Chapter 9. Statements . . . . . . . .
Labels . . . . . . . . . . . . . .
Examples . . . . . . . . . . . .
Related Information . . . . . . . . .
Block . . . . . . . . . . . . . . .
Initialization within Block Statements . .
Example . . . . . . . . . . . . .
Related Information . . . . . . . . .
break . . . . . . . . . . . . . . .
Restrictions. . . . . . . . . . . .
Examples . . . . . . . . . . . .
Related Information . . . . . . . . .
continue . . . . . . . . . . . . . .
Restrictions. . . . . . . . . . . .
Examples . . . . . . . . . . . .
Related Information . . . . . . . . .
do . . . . . . . . . . . . . . . .
Example . . . . . . . . . . . . .
Related Information . . . . . . . . .
Expression . . . . . . . . . . . . .
Examples . . . . . . . . . . . .
Resolving Ambiguous Statements in C++ .
for . . . . . . . . . . . . . . . .
Examples . . . . . . . . . . . .
Related Information . . . . . . . . .
goto . . . . . . . . . . . . . . .
Example . . . . . . . . . . . . .
if . . . . . . . . . . . . . . . .
Examples . . . . . . . . . . . .
null . . . . . . . . . . . . . . . .
Example . . . . . . . . . . . . .
return . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
195
195
195
195
196
196
197
197
197
198
198
199
199
199
200
201
201
201
202
202
202
202
203
204
205
206
206
207
207
208
208
208
Contents
vii
Value
. .
. .
. .
. .
. .
. .
. .
. .
. .
viii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
209
209
210
210
211
212
214
214
214
214
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
215
215
216
216
217
217
218
221
221
221
222
222
222
223
223
224
224
225
225
226
232
233
234
235
235
236
236
236
237
238
238
238
241
242
243
243
244
245
246
247
247
248
248
249
249
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
250
250
251
253
254
256
256
258
259
261
262
263
264
266
267
267
267
268
268
270
271
271
271
272
273
273
273
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
277
277
277
278
278
279
280
282
282
282
283
284
285
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
287
287
288
288
289
289
289
290
290
290
291
291
Contents
ix
Pointers to Members . . . . . .
CBC3X11B . . . . . . . . .
The this Pointer . . . . . . . .
CBC3X11C . . . . . . . . .
CBC3X11D . . . . . . . . .
Static Members . . . . . . . .
Using the Class Access Operators
Static Data Members . . . . .
Static Member Functions . . . .
Member Access . . . . . . . .
Classes and Access Control . .
Access Specifiers . . . . . .
Friends . . . . . . . . . . .
CBC3X11I . . . . . . . . .
CBC3X11J . . . . . . . . .
Friend Scope . . . . . . . .
Friend Access . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
with Static
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Members
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
292
293
293
294
294
295
296
297
299
299
300
300
301
302
302
303
304
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
305
305
305
305
306
306
307
308
308
309
309
310
311
311
311
312
312
313
313
314
314
316
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
317
317
318
318
318
319
320
320
322
324
325
325
326
326
327
Explicit Initialization . . . . . . . . . .
Initializing Base Classes and Members . .
Construction Order of Derived Class Objects
Copying Class Objects . . . . . . . . .
Copy Restrictions . . . . . . . . . .
Copy by Assignment . . . . . . . . .
Copy by Initialization . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
327
329
330
331
331
331
332
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
335
335
336
337
337
338
338
339
339
340
340
341
342
342
343
345
347
347
348
349
350
350
351
353
354
355
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
357
357
358
359
359
359
360
362
362
363
364
365
365
365
366
366
367
368
368
369
370
Contents
xi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
373
373
374
374
376
376
377
378
379
379
379
380
381
382
383
384
384
385
385
385
386
386
386
386
387
xii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
391
391
391
391
392
392
392
392
392
393
393
393
393
393
393
393
394
394
394
394
394
394
394
395
395
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
401
401
401
402
402
403
403
404
404
404
405
405
405
405
406
407
407
408
409
409
410
410
Notices . .
Programming
Trademarks.
Standards .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
411
412
412
413
Glossary
|
|
|
|
. . . . . . . . . . . . . 399
. . . . . . . .
Interface Information
. . . . . . . .
. . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . . . . . . . . . . . . . . . . . . . . . . . . . 415
Bibliography . .
OS/390 . . . .
OS/390 C/C++ .
OS/390 Language
Assembler . . .
COBOL . . . .
PL/I . . . . .
VS FORTRAN. .
CICS . . . . .
DB2 . . . . .
IMS/ESA. . . .
QMF . . . . .
DFSMS . . . .
INDEX
.
.
.
.
. . . . .
. . . . .
. . . . .
Environment
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
443
443
443
443
443
444
444
444
444
444
445
445
445
. . . . . . . . . . . . . . . . . . . . . . . . . . . 447
Contents
xiii
xiv
Part 1. Introduction
This part describes how to use the OS/390 C/C++ Language Reference, and how
to find additional information in the OS/390 C/C++ library. This part introduces the
IBM OS/390 C/C++ product.
Chapter 1. About This Book
Describes how to use this book in relation to the OS/390 C/C++ information
library and related OS/390 documentation.
Chapter 2. About IBM OS/390 C/C++
Introduces the OS/390 C/C++ product and its key features, related OS/390
environments such as OS/390 UNIX System Services, and other OS/390
tools that are useful when using OS/390 C/C++.
APAR and BOOKS files (Shipped with Partitioned data set CBC.SCBCDOC on the product tape contains the
Program materials)
members, APAR and BOOKS, which provide additional information for using
the IBM OS/390 C/C++ licensed program, including:
v Isolating reportable problems
v Keywords
v Preparing an Authorized Program Analysis Report (APAR)
v Problem identification worksheet
v Maintenance on OS/390
v Late changes to OS/390 C/C++ publications
Note: For complete and detailed information on linking and running with OS/390 Language Environment and using
the OS/390 Language Environment runtime options, refer to OS/390 Language Environment Programming Guide,
SC28-1939. For complete and detailed information on using interlanguage calls, refer to OS/390 Language
Environment Writing Interlanguage Applications, SC28-1943.
The following table lists the OS/390 C/C++ and related publications. The table
groups the publications according to the tasks they describe.
Table 2. Publications by Task
Tasks
Books
Books
Installing
Coding programs
v
v
v
v
v
v
v
v
v
v
v
v
v
v
v
OS/390
OS/390
OS/390
OS/390
Debugging programs
v
v
v
v
v
v
README file
Debug Tool Users Guide and Reference, SC09-2137
OS/390 C/C++ Users Guide, SC09-2361
OS/390 C/C++ Programming Guide, SC09-2362
OS/390 Language Environment Programming Guide, SC28-1939
OS/390 Language Environment Debugging Guide and Run-Time
Messages, SC28-1942
OS/390 UNIX System Services Messages and Codes, SC28-1908
OS/390 UNIX System Services Users Guide, SC28-1891
OS/390 UNIX System Services Command Reference, SC28-1892
OS/390 UNIX System Services Programming Tools, SC28-1904
v
v
v
v
Books
Working in the OS/390 UNIX System Services v OS/390 UNIX System Services Parallel Environment: Operation
Parallel Environment
and Use, SC33-6697
v OS/390 UNIX System Services Parallel Environment: MPI
Programming and Subroutine Reference, SC33-6696
|
|
|
Quick reference
Note: For information on using the prelinker, see the appendix on prelinking and linking OS/390 C/C++ programs in
OS/390 C/C++ Users Guide. As of Release 4, this appendix contains information that was previously in the chapter on
prelinking and linking OS/390 C/C++ programs in OS/390 C/C++ Users Guide. It also contains prelinker information
that was previously in OS/390 C/C++ Programming Guide.
Hardcopy Books
The following OS/390 C/C++ books are available in hardcopy:
v OS/390 C/C++ Run-Time Library Reference, SC28-1663
v OS/390 C/C++ Users Guide, SC09-2361
v OS/390 C/C++ Programming Guide, SC09-2362
v OS/390 C/C++ Reference Summary, SX09-1313
v OS/390 C/C++ IBM Open Class Library Users Guide, SC09-2363
v OS/390 C Curses, SC28-1907
v OS/390 C/C++ Compiler and Run-Time Migration Guide, SC09-2359
v Debug Tool Users Guide and Reference, SC09-2137
You can purchase these books on their own, or as part of a set. You receive
OS/390 C/C++ Compiler and Run-Time Migration Guide, SC09-2359 at no charge.
Feature code 8009 includes the remaining books.
PDF Books
All of the OS/390 C/C++ publications are supplied in PDF format. The books are
available on a CD-ROM called OS/390 PDF Library Collection, SK2T-6718. They
are also available at the following Web Site:
http://www.ibm.com/software/ad/c390/cmvsdocs.html
To read a PDF file, use the Adobe Acrobat Reader. If you do not have the Adobe
Acrobat Reader, you can download it for free from the Adobe Web Site:
http://www.adobe.com
Softcopy Books
All of the OS/390 C/C++ publications (except for OS/390 C/C++ Reference
Summary) are available in softcopy book format. The books are available on the
tape that accompanies the OS/390 product, and on a CD-ROM called IBM Online
Library Omnibus Edition OS/390 Collection, SK2T-6700.
|
|
|
Softcopy Examples
Most of the larger examples in the following books are available in
machine-readable form:
v OS/390 C/C++ Language Reference, SC09-2360
v OS/390 C/C++ Users Guide, SC09-2361
v OS/390 C/C++ Programming Guide, SC09-2362
v OS/390 C/C++ IBM Open Class Library Users Guide, SC09-2363
v OS/390 C/C++ IBM Open Class Library Reference, SC09-2364
In the following books, a label on an example indicates that the example is
distributed in softcopy. The label is the name of a member in the data sets
CBC.SCBCSAM or CBC.SCLBSAM. The labels have the form CBCxyyy or CLBxyyy, where
x refers to a publication:
v R and X refer to OS/390 C/C++ Language Reference, SC09-2360
v G refers to OS/390 C/C++ Programming Guide, SC09-2362
v U refers to OS/390 C/C++ Users Guide, SC09-2361
v A refers to OS/390 C/C++ IBM Open Class Library Users Guide, SC09-2363
Examples labelled as CBCxyyy appear in OS/390 C/C++ Language Reference,
OS/390 C/C++ Programming Guide, and OS/390 C/C++ Users Guide. Examples
labelled as CLBxyyy appear in OS/390 C/C++ IBM Open Class Library Users
Guide.
An exception applies to the example names for the Collection Class Library which
do not follow a naming convention. These examples are in OS/390 C/C++ IBM
Open Class Library Reference, SC09-2364.
This page contains late-breaking information about the OS/390 C/C++ product,
including the compiler, the class libraries, and utilities. It also contains a tutorial on
the source level interactive debugger. There are links to other useful information,
such as the OS/390 C/C++ information library and the libraries of other OS/390
elements that are available on the Web. The OS/390 C/C++ home page also
contains samples that you can download, and links to other related Web sites.
%&
%&
optional_item
%&
v If you can choose from two or more items, they are vertical in a stack.
If you must choose one of the items, one item of the stack is on the main path.
%% statement
required_choice1
required_choice2
%&
If choosing one of the items is optional, the entire stack is below the main path.
%% statement
optional_choice1
optional_choice2
v An arrow that returns to the left above the main line indicates an item that you
can repeat.
10
%&
%% statement '
repeatable_item
%&
A repeat arrow above a stack indicates that you can make more than one choice
from the stacked items, or repeat a single choice.
v Keywords are not italicized, and should be entered exactly as shown (for
example, pragma). You must spell keywords exactly as shown in the syntax
diagram. Variables are in lowercase italics (in hardcopy), for example, identifier.
They represent user-supplied names or values.
v If the syntax diagram shows punctuation marks, parentheses, arithmetic
operators, or other nonalphanumeric characters, you must enter them as part of
the syntax.
Note: You do not always require the white space between tokens. You should,
however, include at least one blank space between tokens unless otherwise
specified.
The following syntax diagram example shows the syntax for the #pragma comment
directive.
%%
% (
(1)
(5)
(2)
pragma
(6)
compiler
date
timestamp
copyright
user
(3)
comment
(4)
(7)
"
token_sequence
"
(9)
(10)
%&
(8)
Notes:
1
The comment type must be entered only as one of the following: compiler,
date, timestamp, copyright, or user.
A character string must follow the comma. The character string must be
enclosed in double quotation marks.
10
The following examples of the #pragma comment directive are syntactically correct
according to the diagram above:
Chapter 1. About This Book
11
#pragma comment(date)
#pragma comment(user)
#pragma comment(copyright,"This text will appear in the module")
12
|
|
OS/390 C/C++ has made the following performance and usability enhancements for
this release:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GOFF
|
|
|
|
|
IPA Level 2
|
|
|
|
|
COMPACT
13
|
|
|
|
|
|
|
|
|
For details on how to use this compiler option, see the chapter Compiler Options in
OS/390 C/C++ Users Guide.
|
|
|
|
The IBM System Object Model (SOM) is no longer supported in the C++ compiler
and the IBM Open Class Library. The SOM-enabled class library DLLs have been
stabilized at the V2R9 level and continue to be shipped as a run-time environment
only. You cannot use the V2R10 Compiler to build SOM applications.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For example, a company may use OS/390 Release 10 with Language Environment
on a development system where applications are coded, link-edited, and tested,
while using any supported lower release of OS/390 Language Environment on their
production systems where the finished application modules are used.
|
|
|
|
Downward compatibility support is not the roll-back of new function to prior releases
of OS/390. Applications developed that exploit the downward compatibility support
must not use any Language Environment function that is unavailable on the lower
release of OS/390 where the application will be used.
|
|
|
|
The downward compatibility support includes toleration PTFs for lower releases of
OS/390 to assist in diagnosing applications that do not meet the programming
requirements for this support. (Specific PTF numbers can be found in the PSP
buckets.)
|
|
|
|
14
|
|
|
|
|
|
The C Language
The C language is a general purpose, versatile, and functional programming
language that allows a programmer to create applications quickly and easily. C
provides high-level control statements and data types as do other structured
programming languages. It also provides many of the benefits of a low-level
language.
|
|
The C and C++ compilers offer many features to help your work:
v Optimization support:
Algorithms to take advantage of S/390 architecture to get better optimization
for speed and use of computer resources through the OPTIMIZE and IPA
compiler options.
The OPTIMIZE compiler option, which instructs the compiler to optimize the
machine instructions it generates to produce faster-running object code to
improve application performance at run time.
Interprocedural Analysis (IPA), to perform optimizations across compilation
units, thereby optimizing application performance at run time.
v DLLs (dynamic link libraries) to share parts among applications or parts of
applications, and dynamically link to exported variables and functions at run time.
DLLs allow a function reference or a variable reference in one executable to use
a definition located in another executable at run time. You can use both
Chapter 2. About IBM OS/390 C/C++
15
16
|
|
- const_cast
Explicit specifier
Mutable specifier
Namespace
Run-Time Type Identification (RTTI)
17
Utilities
The OS/390 C/C++ compilers provide the following utilities:
v The CXXFILT Utility to map OS/390 C++ mangled names to the original source.
v The localedef Utility to read the locale definition file and produce a locale object
that the locale-specific library functions can use.
v The DSECT Conversion Utility to convert descriptive assembler DSECTs into
OS/390 C/C++ data structures.
OS/390 Language Environment provides the following utilities:
v The Object Library Utility (C370LIB) to update partitioned data set (PDS and
PDS/E) libraries of object modules and Interprocedural Analysis (IPA) object
modules.
v The DLL Rename Utility to make selected DLLs a unique component of the
applications with which they are packaged. The DLL Rename Utility does not
support XPLINK.
v The prelinker which combines object modules that comprise an OS/390 C/C++
application, to produce a single object module. The prelinker supports only object
and extended object format input files, and does not support GOFF.
|
|
|
|
|
|
|
|
|
Class Libraries
IBM OS/390 C/C++ provides a base set of class libraries, called C/C++ IBM Open
Class, which is consistent with that available in other members of the VisualAge
C++ Version 3.0 product family. These class libraries are:
v The I/O Stream Class Library
The I/O Stream Class Library lets you perform input and output (I/O) operations
independent of physical I/O devices or data types that are used. You can code
sophisticated I/O statements easily and clearly, and define input and output for
your own data types. You can improve the maintainability of programs that use
input and output by using the I/O Stream Class Library.
v The Complex Mathematics Class Library
The Complex Mathematics Class Library lets you manipulate and perform
standard arithmetic on complex numbers. Scientific and technical fields use
complex numbers.
v The Application Support Class Library
The Application Support Class Library provides the basic abstractions that are
needed during the creation of most C++ applications, including String, Date,
Time, and Decimal.
v The Collection Class Library
The Collection Class Library implements a wide variety of classical data
structures such as stack, tree, list, hash table, and so on. Most programs use
collections. You can develop programs without having to define every collection.
Programmers can start programming by using a high level of abstraction, and
later replace an abstract data type with the appropriate concrete implementation.
Each abstract data type has a common interface for all of its implementations.
The Collection Class Library provides programmers with a consistent set of
building blocks from which they can derive application objects. The library design
exploits features of the C++ language such as exception handling and template
support.
All of the libraries that are described above are thread-safe.
18
All of the libraries that are described above are available in both static and DLL
formats. OS/390 C/C++ packages the Application Support Class and Collection
Class libraries together in a single DLL. For compatibility, separate side-decks are
available for the Application Support Class and Collection Class libraries, in addition
to the side-deck available for the combined library.
Note: Retroactive to OS/390 Version 1 Release 3, the IBM Open Class Library is
licensed with the base operating system. This enables applications to use
this library at run time without having to license the OS/390 C/C++ compiler
feature(s) or to use the DLL Rename Utility.
|
|
|
|
|
|
|
|
|
|
|
|
|
The DLLs for the Open Class libraries are compiled without XPLINK. If you use
these DLLs with XPLINK applications, the performance gain you realize in your
application code by using XPLINK may be offset partially or completely (depending
on the frequency of use of DLL functions) by the cost of switching to the non-XPLINK
environment when crossing the boundary between your application code and the
class library code in the DLL. If you use these DLLs with XPLINK applications, you
may notice reduced performance. There are two ways to avoid this problem:
v Use the static library instead of the DLL. This static library has both the XPLINK
and NOXPLINK versions of the objects.
v For the Application Support Class Library or Collection Class Library, recompile
the source code that is shipped with OS/390 C/C++. For build instructions, refer
to the CBC.SCLDBLD readme file.
You can specify either data sets or hierarchical file system (HFS) files as source
files.
|
|
Note: You can also use the dbx shell command to debug programs, as described in
OS/390 UNIX System Services Command Reference, SC28-1892.
Chapter 2. About IBM OS/390 C/C++
19
For further information, see IBM C/C++ Productivity Tools for OS/390.
20
C/C++
Language
Specific
Library
COBOL
Language
Specific
Library
PL/I
Language
Specific
Library
FORTRAN
Language
Specific
Library
The common execution environment is composed of data items and services that
are included in library routines available to an application that runs in the
environment. The OS/390 Language Environment provides a variety of services:
v Services that satisfy basic requirements common to most applications. These
include support for the initialization and termination of applications, allocation of
storage, interlanguage communication (ILC), and condition handling.
v Extended services that are often needed by applications. OS/390 C/C++ contains
these functions within a library of callable routines, and include interfaces to
operating system functions and a variety of other commonly used functions.
v Runtime options that help in the execution, performance, and diagnosis of your
application.
v Access to operating system services; OS/390 UNIX services are available to an
application programmer or program through the OS/390 C/C++ language
bindings.
v Access to language-specific library routines, such as the OS/390 C/C++ library
functions.
For more information, see the Language Environment home page at the following
web address:
http://www.ibm.com/s390/le/
21
The prelinker provided with OS/390 Language Environment combines the object
modules comprising an OS/390 C/C++ application and produces a single object
module. You can link-edit the object module into a load module (which is stored in a
PDS), or bind it into a load module or a program object stored in a PDS, PDSE, or
HFS file.
|
|
Note: For further information on the binder, refer to the DFSMS home page at
http://www.ibm.com/storage/software/sms/smshome.htm.
22
ar
BPXBATCH
c89
dbx
gencat
iconv
lex
localedef
make
yacc
mkcatdefs
runcat
dspcat
dspmsg
Displays a selected message from a message catalog
v The OS/390 UNIX Debugger feature, which provides the dbx interactive symbolic
debugger for OS/390 UNIX applications
v OS/390 UNIX, which provides access to a hierarchical file system (HFS), with
support for the POSIX.1 and XPG4 standards
v OS/390 C/C++ I/O routines, which support using HFS files, standard OS/390
data sets, or a mixture of both
v Application threads (with support for a subset of POSIX.4a)
v Support for OS/390 C/C++ DLLs
OS/390 UNIX offers program portability across multivendor operating systems, with
support for POSIX.1, POSIX.1a (draft 6), POSIX.2, POSIX.4a (draft 6), and
XPG4.2.
To application developers who have worked with other UNIX environments, the
OS/390 UNIX Shell and Utilities are a familiar environment for C/C++ application
development. If you are familiar with existing MVS development environments, you
may find that the OS/390 UNIX environment can enhance your productivity. Refer to
OS/390 UNIX System Services Users Guide for more information on the Shell and
Utilities.
For more information, see the OS/390 UNIX home page at the following web
address:
http://www.ibm.com/s390/unix/
23
I/O Interfaces
The C/C++ runtime library supports the following I/O interfaces:
C Stream I/O
This is the default and the ANSI-defined I/O method. This method
processes all input and output by character.
Record I/O
The library can also process your input and output by record. A record is a
set of data that is treated as a unit. It can also process VSAM data sets by
record. Record I/O is an OS/390 C/C++ extension to the ANSI standard.
TCP/IP Sockets I/O
OS/390 UNIX provides support for an enhanced version of an
industry-accepted protocol for client/server communication that is known as
sockets. A set of C language functions provides support for OS/390 UNIX
sockets. OS/390 UNIX sockets correspond closely to the sockets that are
used by UNIX applications that use the Berkeley Software Distribution
(BSD) 4.3 standard (also known as OE sockets). The slightly different
interface of the X/Open CAE Specification, Networking Services, Issue 4, is
supplied as an additional choice. This interface is known as X/Open
Sockets.
The OS/390 UNIX socket application program interface (API) provides
support for both UNIX domain sockets and Internet domain sockets. UNIX
domain sockets, or local sockets, allow interprocess communication within
OS/390 independent of TCP/IP. Local sockets behave like traditional UNIX
sockets and allow processes to communicate with one another on a single
system. With Internet sockets, application programs can communicate with
others in the network using TCP/IP.
24
In addition, the C++ I/O Stream Library supports formatted I/O in C++. You can
code sophisticated I/O statements easily and clearly, and define input and output for
your own data types. This helps improve the maintainability of programs that use
input and output.
File Types
In addition to conventional files, such as sequential files and partitioned data sets,
the C/C++ runtime library supports the following file types:
Virtual Storage Access Method (VSAM) Data Sets
OS/390 C/C++ has native support for three types of VSAM data
organization:
v Key-sequenced data sets (KSDS). Use KSDS to access a record through
a key within the record. A key is one or more consecutive characters that
are taken from a data record that identifies the record.
v Entry-sequenced data sets (ESDS). Use ESDS to access data in the
order it was created (or in the reverse order).
v Relative-record data sets (RRDS). Use RRDS for data in which each
item has a particular number (for example, a telephone system with a
record associated with each number).
For more information on how to perform I/O operations on these VSAM file
types, see OS/390 C/C++ Programming Guide.
Hierarchical File System Files
OS/390 C/C++ recognizes Hierarchical File System (HFS) file names. The
name specified on the fopen() or freopen() call has to conform to certain
rules (described in OS/390 C/C++ Programming Guide). You can create
regular HFS files, special character HFS files, or FIFO HFS files. You can
also create links or directories.
Memory Files
Memory files are temporary files that reside in memory. For improved
performance, you can direct input and output to memory files rather than to
devices. Since memory files reside in main storage and only exist while the
program is executing, you primarily use them as work files. You can access
memory files across load modules through calls to non-POSIX system()
and C fetch(); they exist for the life of the root program. Standard streams
can be redirected to memory files on a non-POSIX system() call using
command line redirection.
Hiperspace Expanded Storage
Large memory files can be placed in Hiperspace expanded storage to free
up some of your home address space for other uses. Hiperspace expanded
storage or high performance space is a range of up to 2 gigabytes of
contiguous virtual storage space. A program can use this storage as a
buffer (1 gigabyte = 230 bytes).
25
v
v
v
v
26
DB2 programs manage data that is stored in relational databases. You can
access the data by using a structured set of queries that are written in Structured
Query Language (SQL).
The DB2 program uses SQL statements that are embedded in the program. The
SQL translator (DB2 preprocessor) translates the embedded SQL into host
language statements that perform the requested functions. The OS/390 C/C++
compilers compile the output of the SQL translator. The DB2 program processes
a request, and processing returns to the application.
v Data Window Services (DWS)
The Data Window Services (DWS) part of the Callable Services Library allows
your OS/390 C or OS/390 C++ program to manipulate temporary data objects
that are known as TEMPSPACE and VSAM linear data sets.
v Information Management System (IMS)
The Information Management System/Enterprise Systems Architecture (IMS/ESA)
product provides support for hierarchical databases.
v Interactive System Productivity Facility (ISPF)
OS/390 C/C++ provides access to the Interactive System Productivity Facility
(ISPF) Dialog Management Services. A dialog is the interaction between a
person and a computer. The dialog interface contains display, variable, message,
and dialog services as well as other facilities that are used to write interactive
applications.
v Graphical Data Display Manager (GDDM)
GDDM provides a comprehensive set of functions to display and print
applications most effectively:
A windowing system that the user can tailor to display selected information
Support for presentation and keyboard interaction
Comprehensive graphics support
Fonts including support for double-byte character set (DBCS)
Business image support
Saving and restoring graphic pictures
Support for many types of display terminals, printers, and plotters
v Query Management Facility (QMF)
OS/390 C supports the Query Management Facility (QMF), a query and report
writing facility, which allows you to write applications through a callable interface.
You can create applications to perform a variety of tasks, such as data entry,
query building, administration aids, and report analysis.
v OS/390 Java Support
The Java language supports the Java Native Interface (JNI) for making calls to
and from C/C++. These calls do not use ILC support but rather the Java defined
interface JNI. Java code, which has been compiled using the High Performance
Compiler for Java (HPCJ), will support the JNI interface. There is no distinction
between compiled Java and interpretted Java as far as calls to C or C++.
Description
The OS/390 C/C++ compiler supports long long as a native data type in
LANGLVL(EXTENDED) mode.
OS/390 C/C++ supports multibyte characters for those national languages such as
Japanese whose characters cannot be represented by a single byte.
Chapter 2. About IBM OS/390 C/C++
27
Feature
Description
Extended Precision
Floating-Point Numbers
OS/390 C/C++ provides three S/390 floating-point number data types: single precision
(32 bits), declared as float; double precision (64 bits), declared as double; and
extended precision (128 bits), declared as long double.
Extended precision floating-point numbers give greater accuracy to mathematical
calculations.
As of Release 6, OS/390 C/C++ also supports IEEE 754 floating-point representation.
By default, float, double, and long double values are represented in IBM S/390
floating point format. However, the IEEE 754 floating-point representation is used if you
specify the FLOAT(IEEE754) compile option. For details on this support, see the
description of the FLOAT option in OS/390 C/C++ Users Guide.
|
|
|
|
|
You can redirect the standard streams stdin, stderr, and stdout from the command
line or when calling programs using the system() function.
OS/390 C/C++ provides message text in either American English or Japanese. You can
dynamically switch between the two languages.
OS/390 C/C++ provides a locale definition utility that supports the creation of separate
files of internationalization data, or locales. Locales can be used at run time to
customize the behavior of an application to national language, culture, and coded
character set (code page) requirements. Locale-sensitive library functions, such as
isdigit(), use this information.
The OS/390 C/C++ compiler can compile C/C++ source written in different EBCDIC
code pages. In addition, the iconv utility converts data or source from one code page to
another.
Selected library functions, such as string and character functions, are built into the
compiler to improve performance execution. Built-in functions are compiled into the
executable, and no calls to the library are generated.
Multi-threading
Threads are efficient in applications that allow them to take advantage of any
underlying parallelism available in the host environment. This underlying parallelism in
the host can be exploited either by forking a process and creating a new address
space, or by using multiple threads within a single process. For more information, refer
to the OS/390 C/C++ Programming Guide
Multitasking is a mode of operation where your program performs two or more tasks at
the same time. OS/390 C provides a set of library functions that perform multitasking.
These functions are known as the Multitasking Facility (MTF). MTF uses the
multitasking capabilities of OS/390 to allow a single OS/390 C application program to
use more than one processor of a multiprocessing system simultaneously.
Note: XPLINK is not supported in an MTF environment. You can also use threads to
perform multitasking with or without XPLINK, as described in the OS/390 C/C++
Programming Guide.
OS/390 C provides support for packed structures and unions. Structures and unions
may be packed to reduce the storage requirements of an OS/390 C program or to
define structures that are laid out according to COBOL or PL/I structure layout rules.
|
|
|
|
| Unions
|
Fixed-point (Packed)
Decimal Data
OS/390 C supports fixed-point (packed) decimal as a native data type for use in
business applications. The packed data type is similar to the COBOL data type COMP-3
or the PL/I data type FIXED DEC, with up to 31 digits of precision.
The Application Support Class Library provides the Binary Coded Decimal Class for
C++ programs.
28
|
|
|
|
|
Feature
Description
For portability, external names can be mixed case and up to 1024 characters in length.
For C++, the limit applies to the mangled version of the name.
System Calls
You can call commands or executable modules using the system() function under
OS/390, OS/390 UNIX, and TSO. You can also use the system() function to call
EXECs on OS/390 and TSO, or Shell scripts using OS/390 UNIX.
Exploitation of ESA
Support for OS/390, IMS/ESA, Hiperspace expanded storage, and CICS/ESA allows
you to exploit the features of the ESA.
Exploitation of hardware
Use the ARCHITECTURE compiler option to select the minimum level of machine
architecture on which your program will run. ARCH(2) instructs the compiler to generate
faster instruction sequences available only on newer machines. ARCH(3) also generates
these faster instruction sequences and enables support for IEEE 754 Binary
Floating-Point instructions. Code compiled with ARCH(2) runs on a G2, G3, G4, and
2003 processor and code compiled with ARCH(3) runs on a G5 or G6 processor, and
follow-on models.
Use the TUNE compiler option to optimize your application for a selected machine
architecture. TUNE impacts performance only; it does not impact the processor model on
which you will be able to run your application. TUNE(3) optimizes your application for the
newer G4, G5, and G6 processors. TUNE(2) optimizes your application for other
architectures. For information on which machines and architectures support the above
options, refer to the ARCHITECTURE and TUNE compiler information in OS/390 C/C++
Users Guide.
29
30
31
32
33
C Source Programs
A C source program is a collection of one or more directives, declarations, and
statements that is contained in one or more source files. The contents of the
collection of files processed by a single compilation constitutes a compilation unit.
Refer to Glossary on page 415 for a more detailed definition of a compilation unit.
Statements
Directives
Declarations
Definitions
A function declaration 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 declaration declares the function name, its parameters,
and the data type of the value it returns.
A program must contain one, and only one, function called main(). The main()
function is the first function that a program calls when you run the program.
Note: This is not the case for C++ programs. If a C++ program instantiates an
object in file scope, OS/390 C/C++ executes the constructor for that object
first.
By convention, main() is the starting point for running a program. It typically calls
other functions. A program usually stops running at:
v The end of the main() function
v A return statement in the main() function
v An exit function call.
/* Preprocessor directive
*/
double x = 45.0;
*/
double y = NUM;
34
C Source Programs
int main(void)
{
/* Function definition
for main function
*/
double z;
double w;
*/
z = cos(x);
*/
w = cos(y);
printf ("cosine of x is %f\n", z);
printf ("cosine of y is %f\n", w);
}
/* Print cosine of x
/* Print cosine of y
*/
*/
return 0;
This source program defines main() and declares a reference to the functions cos
and printf. The program defines the global variables x and y, initializes them, and
declares two local variables z and w.
C Source Files
A C source file is a text file that contains all or part of a C source program. It can
include any of the functions that the program needs. To create an executable
module or program object, you compile the separate source files individually and
then link or bind them as one program. With the #include directive, you can
combine source files into larger source files. The resulting collection of files that are
seen by the compiler in a single compilation is known as a compilation unit. A
compilation unit does not necessarily constitute the entire program.
A source file contains any combination of directives, declarations, statements, and
definitions. You can split items such as function definitions and large data structures
between source files, but you cannot split them between compiled files. Before you
compile the source file, the preprocessor alters the source file in a predictable way.
The preprocessor directives determine what changes the preprocessor makes to
the source text. As a result of the preprocessing stage, OS/390 C/C++ completes
the preprocessor directives and expands macros. It may create a new source file
that contains C statements, processed directives, declarations, and definitions.
It is sometimes useful to gather variable definitions into 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.
The following example is a C program in two source files. The main() and max()
functions are in separate files. The program starts by running the main() function.
1
2
3
/* Function declaration */
Chapter 3. Introduction to C and C++
35
C Source Files
int main(int argc, char * argv[])
{
int u, w, x, y, z;
/* Function definition
*/
u = 5;
z = 2;
w = max(u, ONE);
x = max(w,TWO);
y = max(x,THREE);
z = max(y,z);
return z;
The first source file declares the function max(), but does not define it. This is an
external declaration, a declaration of a function defined in source file 2. Four
statements in main() are function calls of max().
The lines beginning with a number sign (#) are preprocessor directives. They 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 the function
main() calls four times. After you compile the source files, you can bind and run
them as a single program.
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. OS/390 C/C++
executes the statements within the main() function 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 modular by creating separate functions to perform a
specific task or set of tasks. The main() function calls these functions to perform
the tasks. When your program makes a function call, it executes statements
sequentially. It starts with the first statement in the function until it encounters a
statement that alters the flow of control. 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 you call functions, they
receive values for their parameters from the arguments that you pass in 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 processor that starts
36
Program Execution
the program can pass such values as described in The main() Function on
page 183 .
Scope in C
An identifier becomes visible with its declaration. The region where an identifier is
visible is the identifiers scope. The four kinds of scope are:
v Block
v Function
v File
v Function prototype.
The location of the identifier determines where the identifier is declared. See
Identifiers on page 58 for more information on identifiers.
Block Scope
The identifiers declaration is located inside a statement block. A block starts with an
opening brace ({) and ends with a matching closing brace (}). An identifier with
block scope is visible from the point where you declare it to the closing brace that
ends the block. You can also refer to block scope as local scope.
You can nest block visibility. A block that is nested inside a block can contain
declarations that reuses names declared in the outer block. The new declaration
applies to the inner block. OS/390 C/C++ restores the original declaration when
program control returns to the outer block. A name from the outer block is visible
inside inner blocks that do not redefine the name.
Function Scope
The only type of identifier with function scope is a label name. You implicitly declare
a label by its appearance in the program text. A label is visible throughout the
function that declares it. A goto statement transfers control to the label that is
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 identifiers declaration appears outside of any block or parameter list. It is
visible from the point in the program where you declare it 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. The identifier will be visible to all included files
that appear after the declaration of the identifier. You can declare the identifier again
as a block-scope variable. The new declaration replaces the file-scope declaration
until the end of the block.
Example of Scope in C
The following example declares the variable x on line 1, which is different from the
x it declares on line 2. The declared variable on line 2 has function prototype scope
37
Scope in C
and is visible only up to the closing parenthesis of the prototype declaration. The
variable x declared on line 1 resumes visibility after the end of the prototype
declaration.
1
2
3
4
5
6
7
int x = 4;
/* variable x defined with file scope */
long myfunc(int x, long y); /* variable x has function
*/
/* prototype scope
*/
int main(void)
{
/* . . . */
}
The following program illustrates blocks, nesting, and scope. The example shows
two kinds of scope: file and block. The main() function prints the values 1, 2, 3,
0, 3, 2, 1 on separate lines. Each instance of i represents a different variable.
#include <stdio.h>
int i = 1;
int i = 2, j = 3;
printf("%d\n%d\n", i, j);
{
/* Prints 1 */
/* i and j defined at
block scope */
/* Prints 2, 3 */
int i = 0;
printf("%d\n", i);
/* Prints 2 */
}
printf("%d\n", i);
/* Prints 1 */
return 0;
}
Related Information
v
v
v
v
v
v
v
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 you declare
it.
A file scope identifier has one of the following kinds of linkage:
38
Program Linkage
Internal
Identical identifiers within a single source file refer to the same data
object or function.
External
No linkage
Note: Program linkage is not the same as a function calling convention, which you
can refer to as linkage. While it relates to program linkage, a calling
convention concerns itself with C++ linkage specifications and the use of
certain keywords. This section only discusses program linkage.
Use linkage specifications to link to non-C++ declarations. In C, the #pragma
linkage directive specifies non-C declarations.
See Linkage Specifications Linking to non-C++ Programs on page 50 for more
information.
Internal Linkage
The following kinds of identifiers have internal linkage:
v All 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.
v C++ inline functions.
v C++ identifiers declared at file scope with the specifier const and not explicitly
declared extern. In C, const objects have external linkage by default.
You can define a variable that has static storage class within a block or outside a
function. If the definition occurs within a block, the variable has internal linkage and
is only visible within the block after you can see its declaration. If the definition
occurs outside a function, the variable has internal linkage. It is available from the
point where it is defined to the end of the current source file.
A class is local to its compilation unit if it has no static members or no inline
member functions, and if it has not been used in the declaration of an object,
function, or class.
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.
External Linkage
The following kinds of identifiers have external linkage:
v Identifiers with file or block scope that have the keyword extern in their
declarations, and the previously visible declaration is not static.
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.
v Function identifiers declared without storage-class specifiers.
v Object identifiers that have file scope declarations without a storage-class
specified. OS/390 C/C++ allocates storage for such object identifiers.
v Static class members and no inline member functions.
39
Program Linkage
You can define identifiers that are declared with the keyword extern in other
compilation units.
No Linkage
The following kinds of identifiers have no linkage:
v Identifiers that do not represent an object or a function, including labels,
enumerators, typedef names, type names, and template names
v Identifiers that represent a function argument
v Identifiers declared inside a block without the keyword extern
Storage Duration
Storage duration determines how long storage for an object exists. An object has
either static storage duration or automatic storage duration, but this depends on its
declaration.
Static storage
Automatic storage
Note: Objects can also have heap storage duration. OS/390 C/C++ creates heap
objects at run time and allocates storage for them by calling a function such
as malloc().
Name Spaces
The compiler sets up name spaces to distinguish among identifiers referring to
different kinds of entities. Identical identifiers in different name spaces do not
interfere with each other, even if they are in the same scope.
You must assign unique names within each name space to avoid conflict. You can
use the same identifier to declare different objects as long as each identifier is
unique within its name space. The syntactic context of an identifier within a program
lets the compiler resolve its name space without ambiguity.
You can redefine identifiers in the same name space but within enclosed program
blocks as described in Scope in C on page 37.
40
Name Spaces
Within each of the following four name spaces, the identifiers must be unique.
v Tags of these types must be unique within a single scope:
Enumerations
Structures and unions
v Members of structures, unions, and classes must be unique within a single
structure, union, or class type.
v Statement labels have function scope and must be unique within a function.
v All other ordinary identifiers must be unique within a single scope:
Function names
Variable names
Names of function parameters
Enumeration constants
typedef names.
Structure tags, structure members, variable names, and statement labels are in four
different name spaces. No conflict occurs among the four items named student in
the following example:
int get_item()
{
struct student
/* structure tag
{
char student[20]; /* structure member
int section;
int id;
} student;
/* structure variable
goto student;
student:;
return 0;
/*
*/
*/
*/
OS/390 C/C++ interprets each occurrence of student 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. When student appears after the goto
statement, OS/390 C/C++ passes control to the null statement label. In other
contexts, the identifier student refers to the structure variable.
Related Information
v
v
v
v
Scope in C on page 37
Identifiers on page 58
Type Specifiers on page 87
Chapter 6. Expressions and Operators on page 133
Command-Line Arguments
The maximum allowable length of a command-line argument for OS/390 Language
Environment is 64K.
OS/390 C/C++ treats arguments that you enter on the command line differently in
different environments. The following lists how argv and argc are handled.
argv[0]
41
Command-Line Arguments
argv[1 to n]
argc
Returns 1
argv[0]
Is a null pointer
argc
Returns 1
argv[0]
Under IMS
Under CICS
argv[0]
argv[1 to n]
argv
argv[0]
argv[1 to n]
argv[0]
argv[1 to n]
The only delimiter for the arguments that are passed to main() is white space.
OS/390 C/C++ uses commas passed to main() by JCL as arguments and not as
delimiters.
The following example appends the comma to the 'one' when passed to main().
//FUNC EXEC PCGO,GPGM='FUNC',
//
PARM.GO=('one',
//
'two')
42
Command-Line Arguments
Related Information
v
v
v
v
v
Data Abstraction
Data abstraction provides the foundation for object-oriented programming. In
addition to providing fundamental data types, object-oriented programming
languages allow you to define your 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.
43
Object-Oriented Programming
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 object.
Classes also contain typedefs, enums, and other classes.
Encapsulation
Another key feature of object-oriented programming is encapsulation. Encapsulation
means a class can hide the details of:
v The representation of its data members
v 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:
v Users of a class do not have to deal with unnecessary implementation details.
v Programs are easier to debug and maintain.
v 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 security mechanism. It is possible to circumvent
the class access controls that make encapsulation possible. The language is
not designed to prevent such misuse.
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.
44
Object-Oriented Programming
a particular function. Application programs can then apply that function to an object
without needing to know the specifics of the class to which the object belongs.
In C++, dynamic binding hides the differences between members of 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.
Dynamic binding is distinguished from static or compile-time binding, which involves
compile-time member function resolution according to the static type of an object
reference.
C++ Programs
C++ programs contain many of the same programming statements and constructs
as C programs:
v C++ has many of the same fundamental types (built-in) data types as C, as well
as some types that are not built-in to C. For example, packed decimal is
supported in C but not C++.
v Like ANSI/ISO C, C++ allows you to declare new names for existing (perhaps
complex) types by using the typedef construct. These new type names are not
new types.
v In general, the scope and storage class rules for C also apply in C++.1
v C and C++ have the same set of arithmetic and logical operators.
A C++ name can identify any of the following:
v An object
v A function
v A set of functions
v An enumerator
1. Note: There are exceptions, for example, the following is legal C but not C++:
typedef int s;
struct s{
int i;
};
void f(structs,s);
45
C++ Programs
v
v
v
v
v
A type
A class member
A template
A value
A label
A declaration introduces a name into a program and can define an area of storage
associated with that name.
An expression can be evaluated 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 non-member function called
main().
The following is a simple C++ program containing declarations, expressions,
statements, and two functions:
46
C++ Programs
CBC3X02D
/**
** A simple C++ program containing declarations,
** expressions, statements, and two functions:
**/
#include <math.h>
// contains definition of fabs()
const double multiplier=2.2;
// variable initialization
const double common_ratio=3.1;
// variable initialization
double geo_series(double a, double r)
// function definition
{
if (r == 1.0)
// if statement
return -1.0;
// return statement
else return -2.0;
};
int main()
// program execution begins here
{
double sum;
// variable declaration
sum = geo_series(multiplier, common_ratio); // function call
// ..
return 0;
}
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:
v Local
v Function
v File
v Class
The scope of a name is determined by the location of the names declaration.
A type name first declared in a function return type has file scope. In the following
example, Y has file scope:
struct Y { int a; int b } foo(int a) { . }
A type name first declared in a function argument list has local scope. In the
following example, X has local scope:
int foo(struct X { int a; int b; } x, int y) {
.
}
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. See Friend Scope on page 303 for more information.
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.
47
Scope in C++
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 variable names from the outer block
are usually visible in the nested block. However, if an outer block name 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. See C++ Scope Resolution Operator (::) on page 138 for
infomation on scope resolution.
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 link 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:
v In a member function of that class
v In a member function of a class derived from that class
v After the . (dot) operator applied to an instance of that class
v After the . (dot) operator applied to an instance of a class derived from that class
v After the -> operator applied to a pointer to an instance of that class
v After the -> (arrow) operator applied to a pointer to an instance of a class
derived from that class
v After the :: (scope resolution) operator applied to the name of a class
v After the :: (scope resolution) operator applied to a class derived from that class.
For more information on class scope, see Scope of Class Names on page 282.
48
CBC3X02F
/**
** Hello World
**/
#include <iostream.h>
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.
CBC3X02G
/**
** Another Hello World, illustrating concatenation with cout
**/
#include <iostream.h>
void main()
{
cout << "Hello "
<< "World"
<< "!"
<< endl;
}
Output operators are 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 classes.
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.
CBC3X02H
/**
** Check for a division by zero condition.
** If one occurs, a message is sent to standard error.
Chapter 3. Introduction to C and C++
49
Input (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. By default,
white space (including blanks, tabs, and new lines) is disregarded by the input
operator. For example:
CBC3X02I
/**
** This example illustrates the cin operator
**/
#include <iostream.h>
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.
50
Linkage Specifications
The syntax is:
%% extern string-literal
declaration
{ '
%&
declaration
The string-literal is used to specify the linkage associated with a particular function.
For example:
CBC3X02J
/**
** This example illustrates linkage specifications
**/
extern "C" int printf(const char*,...);
void main()
{
printf("hello\n");
}
Here the string-literal, "C", tells the C++ compiler that the routine printf(const
char*,...) is a C library function. Note that string literals used in linkage
specifications are not case-sensitive.
Some valid values for string-literal are:
"C++"
Default
"C"
C type linkage
For more information on string literals, see String Literals on page 66. For linkage
specification information, see the OS/390 C/C++ Programming Guide.
If the value of string-literal is not recognized, C type linkage is used.
51
Linkage Specifications
52
Tokens
During preprocessing and compilation, OS/390 C/C++ treats source code as a
sequence of tokens. There are five different types of tokens:
v Identifiers
v Keywords
v Literals
v Operators
v Other separators
You should separate adjacent identifiers, keywords, and literals with white space.
You should separate other tokens by white space to make the source code more
readable. White space includes blanks, horizontal and vertical tabs, new lines, form
feeds, and comments.
v The caret (|) character in ASCII (bitwise exclusive OR symbol), which may be
represented by the equivalent not () character on EBCDIC systems
v The split vertical bar () character in ASCII, which you may represent by the
vertical bar (|) character on EBCDIC systems
v The space character
v The control characters that represent new-line, horizontal tab, vertical tab, and
form feed, and end of string (NULL character).
OS/390 C/C++ uses the number sign (#) character for preprocessing only, and
treats the _ (underscore) character as a normal letter.
The execution character set also includes control characters that represent alert,
backspace, carriage return, and new-line.
In a source file, a record contains one line of source text; the end of a record
indicates the end of a source line.
Copyright IBM Corp. 1996, 2000
53
Character Set
The encoding of the following characters from the basic character set may vary
between the source-code generation environment and the runtime environment:
! # [ ] \ { } | |
The OS/390 C/C++ compiler normalizes the encoding of source files indicated by
the #pragma filetag directive and the LOCALE compile time option to the encoding
defined by code page 1047.
The compiler uses the character set that is specified for the LOCALE option for any
output. This includes:
v Listings that contain identifier names and source code
v String literals and character constants that are emitted in the object code
v Messages generated by the compiler
However, this does not include the source-code annotation in the pseudo-assembly
listings.
Depending on the EBCDIC encoding that your installation uses, you can express
the | and | characters as and respectively. This book refers to the | and |
symbols as the caret and vertical bar, respectively. If you do not specify the
NOLOCALE compile-time option, OS/390 C/C++ does not perform normalization. It
assumes that the character set encoding is the IBM-1047 code page. In this case, it
recognizes both the broken and unbroken vertical bars as the vertical bar. The caret
and logical not sign are recognized as the caret. For a detailed description of the
#pragma filetag directive and the LOCALE option, refer to the description of
internationalization, locales, and character sets in the OS/390 C/C++ Programming
Guide.
The compiler recognizes and supports the additional characters (the extended
character set) which you can meaningfully use in string literals and character
constants. The support for extended characters includes the multibyte character
sets.
OS/390 systems represent multibyte characters by using Shiftout <SO> and Shiftin
<SI> pairs. Strings are of the form:
<SO> x y z <SI>
In the above, two bytes represent each character between the <SO> and <SI>
pairs. OS/390 C/C++ restricts multibyte characters to character constants, string
constants, and comments.
Refer to the OS/390 C/C++ Run-Time Library Reference for a discussion on strings
that are passed to library routines, and to Character Constants on page 65 of this
book for information on character constants. If you specify a lowercase a as part of
an identifier name, you cannot substitute an uppercase A in its place. You must use
the lowercase letter.
Trigraph Sequences
Some characters from the C character set are not available in all environments. You
can enter these characters into a C source program by using a sequence of three
characters that are called a trigraph. The trigraph sequences are:
54
Character Set
??=
??(
??)
??<
??>
??/
??
??!
??-
#
[
]
{
}
\
|
|
number sign
left bracket
right bracket
left brace
right brace
backslash
caret
vertical bar
tilde
Example
some_array??(i??) = n;
Represents:
some_array[i] = n;
Digraph Characters
|
|
|
%: or %%
<:
:>
<%
%>
%:%: or
%%%%
#
[
]
{
}
##
number sign
left bracket
right bracket
left brace
right brace
preprocessor macro concatenation operator
55
Character Set
You can create digraphs by using macro concatenation. OS/390 C/C++ does not
replace digraphs in string literals or in character literals. For example:
char *s = "<%%>"; // stays "<%%>"
switch (c)
{
case '<%' : { /* ... */ } // stays '<%'
case '%>' : { /* ... */ } // stays '%>'
}
Symbol
bitand
&
and
&&
bitor
or
||
xor
compl
and_eq
&=
or_eq
|=
xor_eq
|=
not
not_eq
!=
These keywords are only reserved in C++ programs that are compiled with the
DIGRAPH option. OS/390 C/C++ Users Guide describes the DIGRAPH option.
Comments
Comments begin with the /* characters. They end with the */ characters, and can
span more than one line. You can put comments anywhere the language allows
white space.
The preprocessor replaces comments during preprocessing by a single space
character.
Multibyte characters can also be included within a comment.
Note: The /* or */ characters that are found in a character constant or string literal
do not start or end comments.
In the following program, line 6 is a comment:
56
Comments
1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void)
{
printf("This program has a comment.\n");
/* printf("This is a comment line and will not print.\n"); */
return 0;
}
Because the comment on line 6 is equivalent to a space, the output of this program
is:
This program has a comment.
Because the comment delimiters are inside a string literal, line 5 in the following
program is not a comment.
1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void)
{
printf("This program does not have \
/* NOT A COMMENT */ a comment.\n");
return 0;
}
You cannot nest comments. Each comment ends at the first occurrence of */.
The following example highlights the comments:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define TEST_FUNCTION 0
...
16 #if TEST_FUNCTION
Chapter 4. Lexical Elements of C and C++
57
Comments
17
18
19
20
number = 55;
letter = 'A';
/*number = 44;*/
#endif /*TEST_FUNCTION */
C++ Comments
If the SSCOMM compiler option is in effect when you compile a C program, double
slashes (//) also specify the beginning of a comment. C++ permits double-slash
comments as part of the language definition.
A C++ comment can span more than one physical source line if it is joined into one
logical source line with line-continuation (\) characters. You can represent the
backslash character with a trigraph.
Identifiers
An arbitrary number of letters or digits comprise an identifier. Identifiers provide
names for the following language elements:
v Functions
v Data objects
v Labels
v Tags
v Parameters
v Macros
v Typedefs
v Structure and union members
An identifier has the form:
%%
letter
_
$
'
letter
digit
_
$
%&
58
Identifiers
Although the names of system calls and library functions are not reserved words if
you do not include the appropriate headers, 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 headers when using standard library
functions.
Keywords
Keywords are identifiers that are reserved by the language for special use. Although
you can use them for preprocessor macro names, it is poor programming style.
Only the exact spelling of keywords is reserved. For example, auto is reserved , but
AUTO is not. The following table lists the keywords common to both the C and C++
languages. The ANSI/ISO C language definition includes these keywords:
Table 3. Keywords Common to C and C++
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
_Export
friend
inline
new
operator
private
protected
public
template
this
throw
try
virtual
wchar_t
Future versions of the C++ compiler may reserve the following keywords, so you
should avoid using them in your applications:
Chapter 4. Lexical Elements of C and C++
59
Identifiers
Table 5. C++ Keywords (Future)
bool
const_cast
dynamic_cast
explicit
false
mutable
namespace
reinterpret_cast
static_cast
true
typeid
typename
using
For more information on the #pragma map directive, see map on page 259.
60
Identifiers
CBC3244 ./sum.c:2
v Use the long name support that is provided by the compile-time option LONGNAME.
To use the long name support, you must do the following:
Use the LONGNAME compile-time option when compiling your program.
Use the binder to produce a program object in a PDSE, or use the prelinker.
For more information on the binder, prelinker, and LONGNAME compile-time
option, see the OS/390 C/C++ Users Guide.
Constants
A constant does not change its value while the program is running. The value of
any constant must be in the range of non-negative representable values for its type.
C/C++ contains the following types of constants (also called literals):
v Integer
v Floating-Point
v Fixed-Point Decimal Constants (C Only)
v Character
v String
v Enumeration
61
Constants
Enumerations on page 91 discusses enumeration constants, which belong to the
lexical class of identifiers. For more information on data types, see Type Specifiers
on page 87.
Integer Constants
Integer constants represent integer values. You can represent integer constants in
decimal, hexadecimal, or octal values.
%%
decimal_constant
octal_constant
hexadecimal_constant
l
L
u
U
%&
l
u
U
L
l
L
l
L
Note that the suffixes in the above syntax diagram are not case-sensitive; that is, l
and L are the same to the compiler.
An integer constant without a suffix cannot have a value greater than ULONG_MAX. An
integer constant with a suffix that contains LL cannot have a value greater than
ULONGLONG_MAX. In these cases, the compiler will issue an out of range error
message. For information on the ULONG_MAX and the ULONGLONG_MAX macros, see the
OS/390 C/C++ Run-Time Library Reference.
Data Type
unsuffixed decimal
unsuffixed octal
unsuffixed hexadecimal
suffixed by u or U
suffixed by l or L
suffixed by ll or LL
A plus (+) or minus (-) symbol can precede an integer constant. OS/390 C/C++
treats it as a unary operator rather than as part of the constant value.
62
Constants
Decimal Constants
A decimal constant contains any of the digits 0 through 9. The first digit cannot be 0.
%% digit_1_to_9 '
digit_0_to_9
%&
OS/390 C/C++ interprets integer constants that begin with the digit 0 as an octal
constant, rather than as a decimal constant.
The following are examples of decimal constants:
485976
-433132211
+20
5
Hexadecimal Constants
%%
0x
0X
'
digit_0_to_f
digit_0_to_F
%&
Octal Constants
An octal constant begins with the digit 0 and contains any of the digits 0 through 7.
%% 0 ' digit_0_to_7
%&
Floating-Point Constants
A floating-point constant consists of following parts:
v An integral part
v A decimal point
Chapter 4. Lexical Elements of C and C++
63
Constants
v A fractional part
v An exponent part
v 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.
'
%%
. '
digit
' digit
' digit
digit
exponent
exponent
f
F
l
L
exponent
Exponent:
e
E
+
-
' digit
64
Floating-Point Constant
Value
5.3876e4
53,876
4e-11
0.00000000004
1e+5
100000
7.321E-3
0.007321
3.2E+4
32000
0.5e-6
0.0000005
0.45
0.45
6.e10
60000000000
%&
Constants
%%
'
digit_0_to_9
D
d
' digit_0_to_9
' digit_0_to_9
'
%&
digit_0_to_9
' digit_0_to_9
(size, precision)
1234567890123456D
12345678.12345678D
12345678.d
.1234567890d
12345.99d
000123.990d
0.00D
(16,
(16,
( 8,
(10,
( 7,
( 9,
( 3,
0)
8)
0)
10)
2)
3)
2)
For more information on fixed-point decimal data types, see the OS/390 C/C++
Programming Guide.
Character Constants
A character constant contains a sequence of characters or escape sequences that
are enclosed in single quotation mark symbols.
65
Constants
%%
'
'
character
escape_sequence
'
%&
At least one character or escape sequence must appear in the character constant.
The characters can be any from the source program 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 logical
source line.
The value of a character constant that contains a single character is the numeric
representation of the character in the character set that is used at compile 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. In C++, a character constant can contain only one character.
In C, a character constant has type int. In C++, a character constant has type
char.
A wide character constant has type wchar_t, and is used to represent multibyte
characters. Multibyte characters represent characters that use more than one byte
for their encoding. Each multibyte character requires up to 4 bytes for its encoding.
You can represent the double quotation mark symbol by itself. You must, however,
use the backslash symbol that is followed by a single quotation mark symbol (\') as
an escape sequence to represent the single quotation mark symbol.
You can represent the new-line character by the \n new-line escape sequence. You
can represent the backslash character by the \\ backslash escape sequence.
The following are examples of character constants:
'a'
'0'
'x'
'7'
'C'
'\''
'('
'\n'
'\117'
String Literals
A string constant or literal contains a sequence of characters or escape sequences
that are enclosed in double quotation mark symbols.
The maximum size of a string literal on OS/390 C/C++ is 32,765 bytes.
%%
"
'
character
escape_sequence
"
66
%&
Constants
OS/390 C/C++ appends a null ('\0') character 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.
The compiler retains multiple spaces that are contained within a string constant.
To continue a string on the next line, you can use two or more consecutive strings.
The compiler concatenates adjacent string literals to produce a single string. You
cannot concatenate a wide string constant with a character string constant. For
example:
"hello " "there"
"hello " L"there"
"hello" "there"
*/
*/
*/
Another way to continue a string is to use the line continuation sequence (\ symbol
that is immediately followed by a new-line character). A carriage return must
immediately follow the backslash. In the following example, the string literal second
causes a compile-time error.
char *first = "This string continues onto the next\
line, where it ends.";
/* compiles successfully.
char *second = "The comment makes the \ /* continuation symbol
invisible to the compiler.";
/* compilation error.
*/
*/
*/
Characters in concatenated strings remain distinct. For example, the string \xab
occupies 2 bytes of storage. The first byte contains the value X'ab', and the second
byte contains the value X'00' which is the trailing null character. The string \xa\xb
occupies 3 bytes of storage that contains the values X'0a', X'0b', and X'00'.
Following any concatenation, OS/390 C/C++ appends a '\0' of type char at the
end of each string. C++ library functions find the end of a string by scanning for this
value. For a wide-character string literal, OS/390 C/C++ appends a '\0' of type
wchar_t. For example:
char *first = "Hello ";
char *second = "there";
char *third = "Hello " "there";
A character string constant has type array of char and static storage duration. A
wide character string constant has type array of wchar_t and static storage duration.
You should be careful when modifying string literals because the resulting behavior
depends on whether your strings are stored in read/write static memory. C strings
are read/write by default. C++ strings are readonly by default.
Use the #pragma strings directive to change the default storage for string literals.
strings on page 271 describes the #pragma strings directive.
OS/390 C/C++ stores string literals in static storage which can be modified like any
other storage location. C/C++ has the concept of readonly and writeable strings.
This deals with how C/C++ stores multiple occurrences of strings, rather than
whether or not you can modify the strings.
When a string literal appears more than once in the program source, how that string
is stored depends on whether strings are readonly or writeable. If strings are
readonly, then OS/390 C/C++ allocates only one location for that string. All
occurrences will refer to that one location. If strings are writeable, then each
occurrence of the string will have a separate, distinct storage location.
Chapter 4. Lexical Elements of C and C++
67
Constants
By default, the C compiler will consider strings to be writeable. Note that for
readonly #pragma strings, the compiler will put literal strings in an area of storage
that is potentially read only. For writable #pragma strings, it will put them in an area
of storage that is always modifiable.
Use the escape sequence \n to represent a new-line character as part of the string.
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.
For example:
CBC3X02K
/**
** This example illustrates escape sequences in string literals
**/
#include <iostream.h>
void main ()
{
char *s ="Hi there! \n";
cout << s;
char *p = "The backslash character \\.";
cout << p << endl;
char *q = "The double quotation mark \".\n";
cout << q ;
}
Escape Sequences
You can represent any member of the execution character set by an escape
sequence. You can use escape sequences to put unprintable characters in
character and string literals. For example, you can use escape sequences to put
such characters as tab, carriage return, and backspace into an output stream.
%% \
escape_sequence_character
x hexadecimal_digits
octal_digits
%&
68
Constants
The escape sequences and the characters they represent are:
Escape Sequence
Character Represented
\a
\b
Backspace
\f
\n
New-line
\r
Carriage return
\t
Horizontal tab
\v
Vertical tab
\'
\"
\?
Question mark
\\
Backslash
The value of an escape sequence represents the code point of the code page you
use at run time. OS/390 C/C++ translates escape sequences during preprocessing.
For example, on a system that uses the ASCII character codes, the value of the
escape sequence \x56 is the letter V. On a system that uses EBCDIC character
codes, the value of the escape sequence \xE5 is the letter V.
Use escape sequences only in character constants or in string literals. OS/390
C/C++ issues a message only if it does not recognize an escape sequence.
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. For example:
cout << "The escape sequence \\n." << endl;
The following program prints the character 'a' four times to standard output, and
then prints a new line:
CBC3X02L
/** CBC3X02L
** This example illustrates escape sequences
**/
#include <iostream.h>
void main()
{
char a,b,c,d,e;
a='a';
b=129;
// EBCDIC integer value
c='\201';
// EBCDIC octal value
d='\x81';
// EBCDIC hexadecimal value
e='\n';
cout << a << b << c << d << e;
}
69
Constants
70
Chapter 5. Declarations
A declaration establishes the names and characteristics of data objects and
functions used in a program. A definition allocates storage for data objects or
specifies the body for a function. When you define a type, OS/390 C/C++ does not
allocate storage. This chapter discusses the following topics on declarations:
v Declarations Overview
v Block Scope Data Declarations on page 72
v File Scope Data Declarations on page 73
v
v
v
v
v
Objects on page 74
Storage Class Specifiers on page 74
typedef on page 85
Type Specifiers on page 87
Declarators on page 121
Declarations Overview
Declarations determine the following properties of data objects and their identifiers:
v Scope, which describes the visibility of an identifier in a block or source file. For
a complete description of scope, see Scope in C on page 37.
v Linkage, which describes the association between two identical identifiers. See
Program Linkage on page 38 for more information.
v Storage duration, which describes when the system allocates and frees storage
for a data object. See Storage Duration on page 40 for more information.
v Type, which describes the kind of data the object is to represent.
The lexical order of elements when you declare a data object is as follows:
v Storage duration and linkage specification, that are described in Storage Class
Specifiers on page 74
v Type specification, described in Type Specifiers on page 87
v Declarators, which introduce identifiers and make use of type qualifiers and
storage qualifiers, described in Declarators on page 121
v Initializers, which initialize storage with initial values, described in Initializers on
page 129.
Chapter 8. Functions on page 173 describes function declarations.
All data declarations have the form:
71
Declarations Overview
,
%% '
storage_class_specifier
type_specifier
type_qualifier
' declarator
initializer
%&
C++ Notes:
1. One of the fundamental differences between C++ and C is the placement of
variable declarations. Although you can declare variables in the same way, in
C++, you can put variable declarations anywhere in the program. In C,
declarations must come before any statements in a block.
In the following C++ example, the variable d is declared in the middle of the
main() function:
#include <iostream.h>
void main()
{
int a, b;
cout << "Please enter two integers" << endl;
cin >> a >> b;
int d = a + b;
cout << "Here is the sum of your two integers:" << d << endl;
}
2. A given function, object, or type can have only one definition. It can have more
than one declaration as long as all of the declarations match. If you never call a
function and never take its address, then you do not have to define it. If you
declare an object, but never use it, or use it only as the operand of sizeof, you
do not have to define it. You can declare a given class or enumerator more than
once.
The following table shows examples of declarations and definitions. The identifiers
that are declared in the first column do not allocate storage; they refer to a
corresponding definition. In the case of a function, the corresponding definition is
the code or body of the function. The identifiers that are declared in the second
column allocate storage; they are both declarations and definitions.
Table 7. Examples of Declarations and Definitions
Declarations
double pi = 3.14159265;
struct payroll;
struct payroll {
char *name;
float salary;
} employee;
72
auto
register
static
extern
Initialization
You cannot initialize a variable that is declared in a block scope data declaration
that has the extern storage class specifier.
The types of variables you can initialize and the values that uninitialized variables
receive vary for that storage class specifier. See Storage Class Specifiers on
page 74 for details on the different storage classes.
Storage
The duration and type of storage vary for each storage class specifier.
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
v
v
v
v
v
v
v
v
Chapter 5. Declarations
73
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, a
constant expression must describe the initializer. Otherwise, it must reduce to the
address of a previously declared variable at file scope, possibly added to a constant
expression. Initialization of all variables at file scope takes place before the main
function begins running.
Storage
All objects with file scope data declarations have static storage duration. OS/390
C/C++ allocates storage at run time which it frees when the program stops running.
Related Information
v
v
v
v
Objects
An object is a region of storage that contains a value or group of values. You can
access each value by using its identifier or by using a complex expression that
refers to the object. In addition, each object has a unique data type. OS/390 C/C++
establishes both the identifier and data type of an object 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. You can also use it
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.
In C++ code, you reference objects by variables or references. A variable also
represents the location in storage that contains the value of an object.
You commonly refer to an instance of a class type as a class object. The individual
data members of an instantiated class object are also called objects. The set of all
member objects comprises a class object.
74
Initialization
You can initialize any auto variable except parameters. If you do not initialize an
automatic object, its value is indeterminate. If you provide an initial value, the
expression that represents the initial value can be any valid C or C++ expression.
For structure and union members, the initial value must be a valid constant
expression if you use an initializer list. Each time an objects definition (auto or
register) is encountered during program execution, its initialization, if any, is done.
Note: If you use the goto statement to jump into the middle of a block, automatic
variables defined before the label that is jumped to are not initialized.
Storage
Objects with the auto storage class specifier have automatic storage duration. Each
time a block is entered, storage for auto objects that are defined in that block is
made available. When the block is exited, the objects are no longer available for
use.
Chapter 5. Declarations
75
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 10. The second definition occurs in a nested block on line 13. While
the nested block is running, only the auto_var that is created by the second
definition is available. During the rest of the program, only the auto_var that is
created by the first definition is available.
CBC3RAAF:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/****************************************************
** Example illustrating the use of auto variables **
****************************************************/
#include <stdio.h>
int main(void)
{
void call_func(int passed_var);
auto int auto_var = 1; /* first definition of auto_var
{
*/
int auto_var = 2;
/* second definition of auto_var */
printf("inner auto_var = %d\n", auto_var);
}
call_func(auto_var);
printf("outer auto_var = %d\n", auto_var);
return 0;
The following example uses an array that has the storage class auto to pass a
character string to the function sort. The function 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.
CBC3RAAG:
/*****************************************************************
** Sorted string program -- this example passes an array name **
** to a function
**
*****************************************************************/
#include <stdio.h>
#include <string.h>
int main(void)
{
void sort(char *array, int n);
76
return(0);
When you run the program, interaction with the program could produce:
Output
Enter letters:
Input
zyfab
Output
Related Information
v
v
v
v
77
By specifying
extern "C"
C++
extern "C++
OS
extern "OS"
PLI
extern "PLI"
builtin
extern "builtin"
COBOL
extern "COBOL"
FORTRAN
extern "FORTRAN"
|
|
OS_DOWNSTACK
extern "OS_DOWNSTACK"
|
|
OS_UPSTACK
|
|
OS_NOSTACK
|
|
OS31_NOSTACK
extern "OS31_NOSTACK"
REFERENCE
extern "OS_UPSTACK"
extern "OS_NOSTACK"
extern "REFERENCE"
There are some limitations to using extern to specify non-C++ linkage for a
function. While the C++ language supports overloading, other languages do not.
The implications of this are:
v You cannot overload a function that has non-C++ linkage:
extern "FORTRAN"{int func(int);}
extern "FORTRAN"{int func(int,int);}
// not allowed-compiler
// will issue an error message
v You cannot declare a function with a linkage specification if you have already
used the same function name in a declaration without a linkage specification:
int func(int);
extern "FORTRAN"{int func(int,int);}
// not allowed-compiler
// will issue an error message
v You can overload a function as long as it has C++ (default) linkage. Therefore,
OS/390 C/C++ allows the following series of statements:
extern "FORTRAN"{int func(int,int);}
int func(int);
// function with C++ linkage
int func(int,int);
// overloaded function with C++ linkage
78
// not allowed-compiler
// will issue an error message
For more information, see Using Linkage Specifications in C++ in the OS/390
C/C++ Programming Guide, or refer to OS/390 Language Environment Writing
Interlanguage Applications.
The following fragments illustrate the use of extern "C":
extern "C" int cf();
Linkage compatibility affects all C library functions that accept a user function
pointer as a parameter. Use the extern "C" linkage specification to ensure that the
declared linkages are the same. An example of these library functions is qsort();
refer to the OS/390 C/C++ Run-Time Library Reference for more information.
The following example fragment uses extern "C" with qsort().
#include <stdlib.h>
// function to compare table elements
extern "C" int TableCmp(const void *, const void *); // C linkage
extern void * GenTable();
// C++ linkage
void main() {
void *table;
table = GenTable();
// generate table
qsort(table, 100, 15, TableCmp); // sort table, using TableCmp
// and C library routine qsort();
Initialization
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 do either of the
following:
v Appear as part of the definition and the initial value must be described by a
constant expression.
v Reduce to the address of a previously declared object with static storage
duration. You can modify this object by adding or subtracting an integral constant
expression.
If you do not explicitly initialize an extern variable, its initial value is zero of the
appropriate type. Initialization of an extern object is completed by the time the
program starts running.
Chapter 5. Declarations
79
Storage
extern objects have static storage duration. OS/390 C/C++ allocates memory for
extern objects before the main function begins running. When the program finishes
running, OS/390 C/C++ frees the storage.
Certain program variables with the extern storage class may be constant and never
be updated. If this is the case, it is not necessary to have a copy of these variables
made for every user of the program. In addition, there may be a need to share
constant program variables between C and another language.
In this example, you compile the source file with the RENT option. The executable
code includes the variable rates as you specify the #pragma variable(rates,
NORENT). The writable static includes the variable totals. Each user has a personal
copy of the array totals, and all users of the program share the array rates. This
sharing may yield a performance and storage benefit.
The #pragma variable(varname, NORENT) does not apply to, and has no effect on,
program variables with the static storage class. OS/390 C/C++ always includes
program variables with the static storage class with the writable static. An
informational message appears if you write to a nonreentrant variable when you
specify the C CHECKOUT compile-time option.
When you specify #pragma variable(varname, NORENT) for a variable, ensure that
your program never writes to this variable. Program exceptions or unpredictable
program behavior may result should this be the case. In addition, you must include
#pragma variable(varname, NORENT) in every source file where you reference or
define the variable.
For more information on the RENT and NORENT compile-time options, refer to the
OS/390 C/C++ Users Guide.
The following program shows the linkage of extern objects and functions. It
declares the extern object total 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 example defines
extern function tally in File 2. The function tally can be 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.
80
/**************************************************************
** The program receives the price of an item, adds the
**
** tax, and prints the total cost of the item.
**
**************************************************************/
#include <stdio.h>
int main(void)
{
void tally(void);
extern float total;
/* begin main
*/
/* declaration of function tally */
/* first declaration of total
*/
return(0);
/* end main
*/
/**************************************************************
** This file defines the function tally
**
**************************************************************/
#include <stdio.h>
#define tax_rate 0.05
void tally(void)
{
float tax;
extern float total;
/* begin tally */
/* second declaration of total
scanf("%f", &total);
tax = tax_rate * total;
total += tax;
*/
/* end tally */
float total;
When you run this program and interaction with it, it could produce the following:
Output
Input
99.95
Output
The following program shows extern variables that are used by two functions. Both
functions main and sort can access and change the values of the extern variables
string and length. Consequently, main does not have to pass parameters to sort.
Chapter 5. Declarations
81
return(0);
void sort(void)
{
int gap, i, j, temp;
When you run this program, interacting with it could produce the following:
Output
Enter letters:
Input
zyfab
Output
The following code fragment shows a static variable var1, which gets 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;
Related Information
v
v
v
v
82
Initialization
You can initialize any register object except parameters. If you do not initialize an
automatic object, its value is indeterminate. If you provide an initial value, the
expression that represents the initial value can be any valid C or C++ expression.
For structure and union members, the initial value must be a valid constant
expression if you use an initializer list. The program then sets the object to that
initial value each time it enters the program block that contains the objects
definition.
Storage
Objects with the register storage class specifier have automatic storage duration.
Each time a block is entered, storage for register objects that are defined in that
block is 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 you invoke recursively, OS/390
C/C++ allocates the memory for the variable at each invocation of the block.
Restrictions
You cannot use the register storage class specifier in data scope declarations.
C++ Notes: In C programs, you cannot apply the address (&) operator to register
variables. However, C++ lets you take the address of an object with
the register storage class. For example:
register i;
int* b = &i;
Related Information
v
v
v
v
Chapter 5. Declarations
83
Initialization
You can initialize any static object with a constant expression or an expression
that reduces to the address of a previously declared extern or static object,
possibly modified by a constant expression. If you do not provide an initial value,
the object receives the value of zero of the appropriate type.
Storage
Objects with the static storage class specifier have static storage duration. OS/390
C/C++ allocates the storage for a static variable when the program begins
running. When the program finishes running, it frees the memory.
Usage
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 where the object is defined runs.
If a local static variable is a class object with constructors and destructors, OS/390
C++ constructs the object when control passes through its definition for the first
time. If a constructor creates a local class object, OS/390 C++ calls its destructor
immediately before, or as part of, the calls of the atexit() function.
Restrictions
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:
CBC3RAJ1 (File 1):
/************************************************************************
** Program to illustrate file scope static variables
**
************************************************************************/
#include <stdio.h>
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);
}
return(0);
84
The following program shows the linkage of static identifiers with block scope. The
function test() defines the static variable stat_var. This variable retains its
storage throughout the program, even though test() is the only function that can
refer to stat_var.
CBC3RAAK:
/************************************************************************
** Program to illustrate block scope static variables
**
************************************************************************/
#include <stdio.h>
int main(void)
{
void test(void);
int counter;
for (counter = 1; counter <= 4; ++counter)
test();
}
return(0);
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);
}
=
=
=
=
1
2
3
4
auto_var
auto_var
auto_var
auto_var
=
=
=
=
1
1
1
1
Related Information
v
v
v
v
typedef
A typedef declaration lets you define your own identifiers which you can use in
place of type specifiers such as int, float, and double. A typedef declaration does
not reserve storage. The names you define using typedef are not new data types.
They are synonyms for the data types or combinations of data types they represent.
The syntax of a typedef declaration is:
Chapter 5. Declarations
85
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.
C++ Note: A C++ class defined in a typedef without being named 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;
Similarly, you can use typedef to define a class type (structure, union, or C++
class). For example:
typedef struct {
int scruples;
int drams;
int grains;
} WEIGHT;
You can then use the structure WEIGHT in the following declarations:
WEIGHT
Related Information
v
v
v
v
v
v
v
v
v
v
v
86
Characters on page 87
Floating-Point Variables on page 88
Integer Variables on page 90
Enumerations on page 91
Pointers on page 95
void Type on page 100
Arrays on page 101
Structures on page 107
Unions on page 114
Chapter 11. C++ Classes on page 277
Constructors and Destructors Overview on page 317
%&
Type Specifiers
Type Specifiers
Type specifiers indicate the type of the object or function you are declaring. The
fundamental data types are:
v Characters
v Floating-Point Numbers
v Integers
v Enumerations
v Void
Under the IBM extension (using compiler option LANGLVL(EXTENDED)), the C compiler
also provides the intrinsic type:
v Fixed-point Decimal
|
|
|
In C++, enumerations are not an integral type, but they can be subject to integral
promotion, as described in Integral Promotions on page 167.
You can give names to both fundamental and derived types by using the typedef
specifier.
Characters
There are three character data types: char, signed char, and unsigned char. These
three data types are not compatible. If you specify LANGLVL(ANSI), the C compiler
recognizes char, unsigned char, and signed char as distinct types. They are
always distinct types in C++.
The character data types provide enough storage to hold any member of the
character set you program uses at run time. The amount of storage that is allocated
for a char is implementation-dependent. The OS/390 C/C++ compiler represents a
character by 8 bits, as defined in the CHAR_BIT macro in the <limits.h> header.
The default character type behaves like an unsigned char. To change this default,
use #pragma chars, described in chars on page 243.
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. When a char (signed or unsigned) is widened to an int, its
value is preserved.
To declare a data object that has a character type, use a char type specifier. The
char specifier has the form:
Chapter 5. Declarations
87
Type Specifiers
%%
unsigned
signed
char
%&
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.
Use the char specifier in variable definitions to define such variables as follows:
arrays of characters, pointers to characters, and arrays of pointers to characters.
Use signed char or unsigned char to declare numeric variables that occupy a
single byte.
C++ Note: For the purposes of distinguishing overloaded functions, a C++ char is
a distinct type from signed char and unsigned char.
The following example defines the unsigned char variable switches as having the
initial value 3:
unsigned char switches = 3;
Related Information
v
v
v
v
Floating-Point Variables
There are three types of floating-point variables: float, double, and long double.
The amount of storage that is allocated for a float, a double, or a long double is
implementation-dependent. On all compilers, the storage size of a float variable is
less than or equal to the storage size of a double variable.
To declare a data object that has a floating-point type, use the float specifier.
The float specifier has the form:
88
Type Specifiers
%%
float
double
long double
%&
The following example defines the float variable real_number with the initial value
100.55:
static float real_number = 100.55f;
The following example defines the float variable float_var with the initial value
0.0143:
float float_var = 1.43e-2f;
The following example defines the array table with 20 elements of type double:
double table[20];
Related Information
Chapter 5. Declarations
89
Type Specifiers
Note: <decimal.h> defines DEC_DIG (the maximum number of digits n) and
DEC_PRECISION (the maximum precision p). Currently, it uses a maximum of
31 digits for both limits.
The following examples show how to declare a variable as a fixed-point decimal
data type:
decimal(10,2)
decimal(5,0)
decimal(5)
decimal(18,10)
decimal(8,2)
In
v
v
v
v
x;
y;
z;
*ptr;
arr[100];
constant_expression
Related Information
Integer Variables
Integer variables fall into the following categories:
v short int or short or signed short int or signed short
v signed int or int
v long int or long or signed long int or signed long
v long long int or long long or signed long long int or signed long long
v unsigned short int or unsigned short
v unsigned or unsigned int
v unsigned long int or unsigned long
v unsigned long long int or unsigned long long
Note: OS/390 C/C++ supports the long long data type for language levels other
than ANSI.
The default integer type for a bit field is unsigned. The amount of storage that is
allocated for integer data is implementation-dependent.
OS/390 C/C++ provides three sizes of integer data types. Objects that are of type
short have a length of 2 bytes of storage. Objects that are of type long have a
length of 4 bytes of storage. Objects that are of type long long have a length of 8
bytes of storage. An int data type represents the most efficient data storage size
on the system (the word-size of the machine) and receives 4 bytes of storage.
90
%&
Type Specifiers
The unsigned prefix indicates that 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 that has an integer data type, use an int type specifier.
The int specifier has the form:
%%
unsigned
signed
int
short
long
unsigned
%&
int
long
int
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 you can assign as an integer. The storage class of a
variable determines how you can initialize the variable.
C++ Note: 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. Chapter 13.
C++ Overloading on page 305 describes overloading and argument
matching.
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 as 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;
Related Information
v
v
v
v
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
Chapter 5. Declarations
91
Type Specifiers
in one statement. You can also declare an enumeration type separately from the
definition of variables of that type. You refer to the identifier that is associated with
the data type (not an object) as an enumeration tag.
C++ Note: In C, an enumeration has an implementation-defined integral type. This
restriction does not apply to C++. In C++, an enumeration has a distinct
type that does not have to be integral.
identifier
{ ' enumerator
%&
The keyword enum, that is 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.
C++ Note: In C, each enumerator represents an integer value. In C++, each
enumerator represents a value that you can convert to an integral
value.
An enumerator has the form:
%% identifier
integral_constant_expression
%&
To conserve space, you can store enumerations in spaces smaller than the storage
required by an int data type.
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.
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 you do not assign an explicit value, 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 that is represented by the previous identifier.
In C, enumeration constants have type int.
In C++, each enumeration constant has a value that can be promoted to a signed
or unsigned integer value and a distinct type that does not have to be integral. Use
92
Type Specifiers
an enumeration constant anywhere an integer constant is allowed, or for C++,
anywhere a value of the enumeration type is allowed.
Each enumeration constant must be unique within the scope in which the
enumeration is defined. In the following example, the declarations of average on line
4 and of poor on line 5 cause compiler error messages:
1
2
3
4
5
6
func()
{
enum score { poor, average, good };
enum rating { below, average, above };
int poor;
}
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
*/
*/
In C, 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.
Chapter 5. Declarations
93
Type Specifiers
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;
C++ also lets you put the storage class immediately before the declarator. For
example:
enum score { poor=1, average, good } register rating = good;
Both examples define the enumeration data type score and the variable rating.
Variable rating has the storage class specifier register, the data type enum score,
and the initial value good.
Combining a data type definition with the definitions of all variables which have that
data type lets you leave the data type unnamed. For example:
enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday } weekday;
The above example defines the variable weekday, which you can assign to any of
the specified enumeration constants.
94
"
Type Specifiers
scanf("%d", &num);
weekday=num;
french(weekday);
return(0);
Related Information
v Identifiers on page 58
v Enumeration Constants on page 92
v Constant Expressions on page 139
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:
v To access dynamic data structures such as linked lists, trees, and queues.
v To access elements of an array, or members of a structure, or members of a C++
class.
v To access an array of characters as a string.
v To pass the address of a variable to a function. (In C++, 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. Calling Functions and Passing
Arguments on page 184 describes passing arguments by reference.
Declaring Pointers
The following example declares pcoat as a pointer to an object that has type long:
extern long *pcoat;
Chapter 5. Declarations
95
Type Specifiers
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. In the following example, pvolt is a
constant pointer to an object that has type short:
short * const pvolt;
The following example declares pnut as a pointer to an int object that has the
volatile qualifier:
extern int volatile *pnut;
The following example defines psoup as a volatile pointer to an object that has
type float:
float * volatile psoup;
Assigning 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 */
Initializing Pointers
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 example initializes pointer amount 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. By specifying the name of the array, you can assign the address of the
first element of an array to a pointer. The following two sets of definitions are
equivalent. Both define the pointer student and initialize student to the address of
the first element in section:
96
Type Specifiers
int section[80];
int *student = section;
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";
You can also initialize a pointer to NULL by using any integer constant expression
that evaluates to 0. For example, char * a=0;. Such a pointer is a NULL pointer. It
does not point to any object.
Restrictions on C Pointers
The OS/390 C compiler supports only the pointers that are obtained in one of the
following ways:
v Directly from a malloc/calloc/realloc call
v As an address of a data type (that is, &variable)
v From constants
v Received as a parameter from another C function
v Directly from a call to an OS/390 Language Environment service that allocates
storage, such as CEEGTST
|
|
|
|
|
Note: For details about receiving the parameter list (argv) in C main, please refer
to the OS/390 Language Environment Programming Guide, SC28-1939,
which includes information on preparing your main routine to receive
parameters, and on C and C++ parameter passing considerations.
You cannot use pointers to reference bit fields or objects that have the register
storage class specifier.
Packed and nonpacked objects have different memory layouts. Consequently, a
pointer to a packed structure or union is incompatible with a pointer to a
corresponding nonpacked structure or union. 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. In
the following example, the cast operation lets you compare the two pointers, but
you must be aware that ps1 still points to a nonpacked object:
Chapter 5. Declarations
97
Type Specifiers
int main(void)
{
_Packed struct ss *ps1;
struct ss
*ps2;
.
.
.
ps1 = (_Packed struct ss *)ps2;
.
.
.
}
Using Pointers
You can use two operators when you are working with pointers, the address (&)
operator, and the indirection (*) operator. You can use the & operator to refer to the
address of an object. For example, the following statement assigns the address of x
to the variable p_to_x. It defines the variable p_to_x as a pointer.
int x, *p_to_x;
p_to_x = &x;
The * (indirection) operator lets you access the value of the object a pointer refers
to. 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;
Pointer Arithmetic
You can perform a limited number of arithmetic operations on pointers. These
operations are:
v Increment and decrement
v Addition and subtraction
v Comparison
v Assignment
The increment (++) operator increases the value of a pointer by the size of the data
object the pointer refers to. 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 the pointer refers to. 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.
You can add a pointer to an integer, but you cannot add a pointer to a pointer.
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:
98
Type Specifiers
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 Chapter 6. Expressions and Operators on page 133 for more
information on these operators.
You define pointer comparisons only when the pointers point to elements of the
same array. You can perform pointer comparisons that use the == and != operators
even when the pointers point to elements of different arrays.
You can assign to a pointer the address of a data object, the value of another
compatible pointer or the NULL pointer.
SIZE 20
EXIT_FAILURE 999
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
*/
*/
Chapter 5. Declarations
99
Type Specifiers
return(*arry);
}
return(*arry);
} /* End of find_name */
/* found it!
*/
*/
Input
Mark
Output
OR:
Output
Input
Deborah
Output
Related Information
v
v
v
v
v
void Type
The void data type always represents an empty set of values. The only object that
you can declare with the type specifier void is a pointer.
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 that takes
no arguments is void.
You cannot declare a variable of type void, but you can explicitly convert any
expression to type void. The resulting expression can only be used as one of the
following:
v An expression statement
v The left operand of a comma expression
v The second or third operand in a conditional expression.
Line 7 of the following example declares the function find_max() as having type
void. Lines 15 through 26 contain the complete definition of find_max().
Note: The use of the sizeof operator in line 13 is a standard method of
determining the number of elements in an array.
CBC3RAAM:
1
2
3
4
5
6
7
8
9
10
100
/**
** Example of void type
**/
#include <stdio.h>
/* declaration of function find_max */
extern void find_max(int x[ ], int j);
int main(void)
{
Type Specifiers
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
return(0);
*/
Arrays
An array is an ordered group of data objects. Refer to each object as an element.
All elements within an array have the same data type.
Use any type specifier in an array definition or declaration. Array elements can be
of any data type, except function or, in C++, a reference. You can, however, declare
an array of pointers to functions.
Declaring Arrays
The array declarator contains an identifier that is followed by an optional subscript
declarator. An identifier that is preceded by an * (asterisk) is an array of pointers.
A subscript declarator has the form:
%% [
constant_expression
] '
%&
constant_expression ]
The subscript declarator describes the number of dimensions in the array and the
number of elements in each dimension. Each bracketed expression, or subscript,
describes a different dimension and must be a constant expression. Note that the [
and ] characters can be represented by the trigraphs ??( and ??) respectively.
The following example defines a one-dimensional array that contains four elements
that have type char:
char list[4];
The first subscript of each dimension is 0. 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];
Chapter 5. Declarations
101
Type Specifiers
OS/390 C/C++ stores multidimensional arrays in row-major order. When you are
referring to elements in order of increasing storage location, the last subscript varies
the fastest. For example, consider the following elements of array roster:
roster[0][0]
roster[0][1]
roster[1][0]
roster[1][1]
roster[2][0]
roster[2][1]
roster[0][0]
roster[0][1]
roster[1][0] ...
You can leave the first, and only the first, set of subscript brackets empty in the
following instances:
v Array definitions that contain initializations
v extern declarations
v Parameter declarations.
In array definitions that leave the first set of subscript brackets empty, the initializer
determines 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, OS/390 C/C++ 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, provided the
array has previously been declared. An unsubscripted array name with square
brackets (for example, region[]) is allowed in the following contexts:
v In arrays that are declared at file scope
v In the argument list of a function declaration
In function declarations and declarations with the extern specifier, the only
dimension you can leave empty is the first one. You must specify the sizes of
additional dimensions.
In extended modes, you can also use unsubscripted array names in the following
contexts:
v In union members
v As the last member of a structure
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
you use an array as an operand of the sizeof or the address (&) operator.
Initializing Arrays
102
Type Specifiers
Note: Array initializations can be either fully braced (with braces around each
dimension) or unbraced (with only one set of braces that enclose the entire
set of initializers). Avoid placing braces around some dimensions and not
around others.
The following definition shows a completely initialized one-dimensional array:
static int number[3] = { 5, 7, 2 };
Value
number[0]
number[1]
number[2]
Value
number1[0]
number1[1]
number1[2]
Value
item[0]
item[1]
item[2]
item[3]
item[4]
103
Type Specifiers
These definitions create the following elements:
Element
Value
Element
Value
Element
Value
name1[0]
name1[1]
name1[2]
J
a
n
name2[0]
name2[1]
name2[2]
name2[3]
J
a
n
\0
name3[0]
name3[1]
name3[2]
name3[3]
J
a
n
\0
Note that the following definition would result in the null character being lost:
static char name[3]="Jan";
In C, the compiler accepts name[3] with no warning or error messages. In C++, the
compiler generates an error message that states the character array must be at
least 4 characters in size to accept the string literal. To initialize this array in C++,
use character-by-character initialization, for example:
static char name[3]={'J','a','n'};
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
v Using braces to group the values of the elements you want initialized. You can
put 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 }
};
104
Type Specifiers
The initial values of matrix are:
Element
Value
Element
Value
matrix[0][0]
matrix[0][1]
matrix[0][2]
matrix[0][3]
matrix[1][0]
matrix[1][1]
1
2
0
0
3
4
matrix[1][2]
matrix[1][3]
matrix[2][0]
matrix[2][1]
matrix[2][2]
matrix[2][3]
0
0
5
6
0
0
You cannot have more initializers than the number of elements in the array.
C++ Notes:
1. In C++, you can use a zero-sized array in a class definition, but it must be
non-static.
2. In a class definition, the zero-sized array must be the last non-static data
member. You can use members such as functions, static data members, and
typedefs after the zero-sized array.
3. You cannot use a class that contains a zero-sized array as a base class.
return(0);
Chapter 5. Declarations
105
Type Specifiers
This program produces the following output:
price
price
price
price
price
=
=
=
=
=
$1.41
$1.50
$3.75
$5.00
$0.86
total
total
total
total
total
=
=
=
=
=
$1.48
$1.57
$3.94
$5.25
$0.90
The following program defines the multidimensional array salary_tbl. A for loop
prints the values of salary_tbl.
CBC3RAAP:
/**
** Example of a multidimensional array
**/
#include <stdio.h>
#define ROW_SIZE
3
#define COLUMN_SIZE 5
int main(void)
{
static int salary_tbl[ROW_SIZE][COLUMN_SIZE] =
{
{ 500, 550, 600, 650, 700
},
{ 600, 670, 740, 810, 880
},
{ 740, 840, 940, 1040, 1140
}
};
int grade, step;
for (grade = 0; grade < ROW_SIZE; ++grade)
for (step = 0; step < COLUMN_SIZE; ++step)
{
printf("salary_tbl[%d] [%d] = %d\n", grade, step,
salary_tbl[grade] [step]);
}
}
return(0);
106
[0]
[1]
[2]
[3]
[4]
[0]
[1]
[2]
[3]
[4]
[0]
[1]
[2]
[3]
[4]
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
500
550
600
650
700
600
670
740
810
880
740
840
940
1040
1140
Type Specifiers
Related Information
v
v
v
v
v
v
Pointers on page 95
Array Subscript [ ] (Array Element Specification) on page 141
String Literals on page 66
Declarators on page 121
Initializers on page 129
Chapter 7. Implicit Type Conversions on page 167
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.
Use structures to group logically related objects. For example, to allocate storage
for the components of one address, define the following variables:
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
To allocate storage for more than one address, group the components of each
address by defining a structure data type and as many variables as you need to
have the structure data type.
In the following example, lines 1 through 7 declare the structure tag address:
1
2
3
4
5
6
7
8
9
10
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
struct address perm_address;
struct address temp_address;
struct address *p_perm_address = &perm_address;
The variables perm_address and temp_address are instances of the structure data
type address. Both contain the members described in the declaration of address.
The pointer p_perm_address points to a structure of address and is initialized to
point to perm_address.
Refer to 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 assign a pointer to the string "Ontario" to the
pointer prov that is in the structure perm_address:
perm_address.prov = "Ontario";
p_perm_address -> prov = "Ontario";
All references to structures must be fully qualified. In the example, you cannot
reference the fourth field by prov alone. You must reference this field by
perm_address.prov.
Structures with identical members but different names are not compatible and
cannot be assigned to each other. Structures are not intended to conserve storage.
Chapter 5. Declarations
107
Type Specifiers
If you need direct control of byte mapping, use pointers. Dot Operator (.) on
page 142 and Arrow Operator (>) on page 142 describe structure member
references.
You cannot declare a structure with members of incomplete types. See Incomplete
Types on page 121 for more information.
Declaring a Structure
A structure type declaration describes the members that are part of the structure. It
contains the struct keyword that is followed by an optional identifier (the structure
tag), and a brace-enclosed list of members.
A structure declaration has the form:
%%
_Packed
struct
identifier
%&
{ '
identifier
member ;
The keyword struct followed by the identifier (tag) names the data type. If you do
not provide a tag name to the data type, you must put all variable definitions that
refer to it within the declaration of the data type.
The list of members provides the data type with a description of the values that you
can stored in the structure.
A structure member definition has the form:
,
%% type_specifier '
declarator
.declarator
constant_expression
%&
If a : (colon) and a constant expression follow the member declarator, the member
represents a bit field. A member that does not represent a bit field can be of any
data type and can have the volatile or const qualifier.Declaring and Using Bit
Fields in Structures on page 110 describes bit fields.
You can redefine identifiers that are used as structure or member names 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. You can, however, 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. You can,
however, declare a structure type that contains a pointer to itself as a member.
108
Type Specifiers
C++ Note: The keyword struct is optional in C++.
You can declare structures that have any storage class. Most compilers, however,
treat structures that are declared with the register storage class specifier as
automatic structures.
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. However, you need to initialize all members in the structure prior to the
member of interest. For example, if you are interested in initializing the fifth member
of a structure, you must initialize the first four members, as well. You do not have to
initialize the sixth and subsequent members. You cannot initialize unnamed bit
fields.
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 =
{ 3, "Savona Dr.", "Dundas", "Ontario", "L4B 2A1"};
Value
perm_address.street_no
perm_address.street_name
perm_address.city
perm_address.prov
perm_address.postal_code
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
struct address temp_address =
{ 44, "Knyvet Ave.", "Hamilton", "Ontario" };
Chapter 5. Declarations
109
Type Specifiers
The values of temp_address are:
Member
Value
temp_address.street_no
44
temp_address.street_name
temp_address.city
temp_address.prov
temp_address.postal_code
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
} perm_address, temp_address;
Because this example does not name the structure data type, perm_address and
temp_address are the only structure variables that will have this data type. Putting
an identifier after struct, lets you make additional variable definitions of this data
type later in the program.
The structure type (or tag) cannot have the volatile qualifier, but you can define a
member or a structure variable 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 qualifies the structures file1 and file2, and the structure member
subfile.code as volatile.
110
Type Specifiers
Bit fields with a length of 0 must be unnamed. You cannot reference or initialize
unnamed bit fields. A zero-width bit field causes the next field to be aligned on the
next container boundary where the container is the same size as the underlying
type as the bit field. A _Packed structure, a bit field of length 0, causes the next field
to align on the next byte boundary.
The maximum bit-field length is implementation dependent.
For portability, do not use bit fields greater than 32 bits in size.
The following restrictions apply to bit fields. You cannot:
v Define an array of bit fields
v Take the address of a bit field
v Have a pointer to a bit field
v Have a reference to a bit field (C++ only)
In C, 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.
The default integer type for a bit field is unsigned.
A bit field cannot have the const or volatile qualifier.
The following structure has three bit-field members kingdom, phylum, and genus,
occupying 12, 6, and 2 bits respectively:
struct taxonomy {
int kingdom : 12;
int phylum : 6;
int genus : 2;
};
C++ Note: Unlike ANSI/ISO C, C++ bit fields can be any integral type or
enumeration type. When you assign an out-of-range value to a bit field,
OS/390 C/C++ preserves the low-order bit pattern and assigns the
appropriate bits.
If a series of bit fields does not add up to the size of an int, padding can take
place. OS/390 C/C++ determines the amount of padding by the alignment
characteristics of the structure members. 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;
/* 4 bytes */
unsigned ac : 4;
unsigned : 4;
unsigned clock : 1;
unsigned : 0;
unsigned flag : 1;
} kitchen ;
Chapter 5. Declarations
111
Type Specifiers
The structure kitchen contains eight members that total 16 bytes. The following
table describes the storage that each member occupies:
Member Name
Storage Occupied
light
1 bit
toaster
1 bit
(padding 30 bits)
count
ac
4 bits
(unnamed field)
4 bits
clock
1 bit
(padding 23 bits)
flag
1 bit
(padding 31 bits)
All references to structure fields must be fully qualified. For instance, 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 a value that is out of its range to a bit field, OS/390 C/C++
preserves the bit pattern and assigns the appropriate bits. The following expression
sets the toaster field of the kitchen structure to 0 because it assigns only the least
significant bit to the toaster field:
kitchen.toaster = 2;
112
Type Specifiers
CBC3RAAS:
/**
** Example program illustrating structures using linked lists
**/
#include <stdio.h>
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);
}
return(0);
The structure type record contains two members: the integer number and next_num,
which is a pointer to a structure variable of type record.
The example assigns the following values to the record type variables name1, name2,
and name3:
Member Name
Value
name1.number
144
name1.next_num
name2.number
203
name2.next_num
name3.number
488
name3.next_num
113
Type Specifiers
Alignment of Structures: Normal structure alignment aligns the structure
members on their natural boundaries and ends the structure on its natural
boundary. The alignment of the structure is that of its strictest member. The
compiler performs normal alignment when your program meets one of the following
conditions:
v It does not specify the #pragma pack directive
v It specifies #pragma pack() before the structure declaration
v It specifies #pragma pack(full) before the structure declaration
To change the alignment back to what it was before the last #pragma pack, use the
reset option.
Consider if, by default, the compiler packs data types along boundaries smaller than
those specified by #pragma pack. The compiler still aligns them along the smaller
boundaries. For example, the compiler always aligns type char along a 1-byte
boundary, regardless of the value of #pragma pack.
Consider when more than one #pragma pack directive appears in a structure defined
in an inlined function. In that case, the #pragma pack directive that is in effect at the
beginning of the structure takes precedence.
For information on calling C packed structures from C++, see the OS/390 C/C++
Programming Guide. For information on packing C structures, see _Packed
Qualifier (C Only) on page 124. For information on alignment of unions, see
Alignment of Unions on page 119. For information how to use the #pragma pack
directive to change alignment, see pack on page 266.
Alignment of Nested Structures: A nested structure has the alignment that
precedes its declaration, not the alignment of the structure in which it is contained.
#pragma pack ()
struct nested {
int x;
char y;
int z;
};
// full alignment
#pragma pack(1)
struct packedcxx{
char
a;
short b;
struct nested s1;
};
// 1-byte alignment
// full alignment
Related Information
v
v
v
v
v
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. OS/390 C/C++ overlays the
members 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).
114
Type Specifiers
C++ Notes:
1. In C++, a union can have member functions, including constructors and
destructors, but not virtual member functions. You cannot use a union as a base
class nor derive it from a base class.
2. A C++ union member cannot be a class object that has a constructor,
destructor, or overloaded copy assignment operator. In C++, you cannot declare
a member of a union with the keyword static.
Declaring a Union
%%
qualifier
union
{ '
identifier
member ;
%&
The identifier is a tag you give to the union that is specified by the member list. If
you specify a tag, you can make any subsequent declaration of the union (in the
same scope) by declaring the tag and omitting the member list. If you do not
specify a tag, you must put 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 you
can store in the union.
A union member definition has the form:
,
%% type_specifier '
declarator
.declarator
%&
constant_expression
You can reference one of the possible union members the same way as you
reference a member of a structure.
For example, the following code assigns '\n' to the first element in the character
array birthday, a member of the union people:
union {
char birthday[9];
int age;
float weight;
} people;
people.birthday[0] = '\n';
A union can represent only one of its members at a time. In the example, the union
people contains either age, birthday, or weight but never more than one of these.
The printf statement in the following example does not give the correct result
because people.age replaces the value that is assigned to people.birthday in the
first line:
Chapter 5. Declarations
115
Type Specifiers
1
2
3
people.birthday = "03/06/56";
people.age = 38;
printf("%s\n", people.birthday);
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.
Type Specifier: The type specifier contains the keyword union that is followed by
the name of the union type. You must declare the union data type before you can
define a union that has 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.
Declarator: The declarator is an identifier, possibly with the volatile or const
qualifier.
Initializer: 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 = {"23/07/57"};
116
a;
{
x;
y;
z;
Type Specifiers
union uu
n_array[2];
/* _Packed union is not supported for C++
_Packed union uu
p_array[2];
*/
Because it is not packed, each element in the nonpacked n_array has an alignment
restriction of 2 bytes. (The largest alignment requirement among the union
members is that of short a.) There is 1 byte of padding at the end of each element
to enforce this requirement.
In the packed array, p_array, each element is of type _Packed union uu. Because
every element aligned on the byte boundary, each element has a length of only 3
bytes, instead of the 4 bytes in the previous example.
The following equivalent C++ example uses the #pragma pack directive instead of
the _Packed qualifier:
union uu
short
struct
char
char
char
} b;
};
{
{
x;
y;
z;
a;
union uu
n_array[2];
#pragma pack(pack)
union uu p_array[2];
#pragma pack(reset)
Anonymous Unions in C
You can declare unions without declarators if they are members of another structure
or union. Refer to unions without declarators as anonymous unions. C supports
anonymous unions only when you use the LANGLVL(COMMONC) compiler option.
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;
117
Type Specifiers
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 examples, you can access the members 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 you declare a union 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;
};
You cannot use the variables b and c from this union at file scope, and so the
following statements generate errors:
b = 5;
c = 2.5;
An anonymous union cannot have protected or private members. You must declare
a global anonymous union 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.
118
Type Specifiers
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 example defines an array of structures that is named records. Each
element of records contains three members: the integer id_num, the integer
type_of_input, and the union variable input. The variable 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';
Alignment of Unions: You can perform packing in a union. Each member starts
at offset zero, and the entire union spans as many bytes as its largest element. The
#pragma pack affects the total alignment restriction of the whole union. Consider the
following example:
Without Packing:
union uu
short
struct
char
char
char
} b;
};
union uu
{
{
x;
y;
z;
a;
array[2];
First, consider the non-packed array. Each of its elements is of type union uu.
Since it is non-packed, every element has an alignment restriction of 2 bytes. The
largest alignment requirement among the union members is that of short a. There
is one byte of padding at the end of each element to enforce this requirement.
Chapter 5. Declarations
119
Type Specifiers
array[0] array[1]
x y z
x y z
0
1
2
3
4
5
6
7
8
a;
{
x;
y;
z;
union uu
p1_array[2];
Now consider the packed array p1_array. Since the example specifies #pragma
pack(packed), the alignment restriction of every element is the byte boundary.
Therefore, each element has a length of only 3 bytes, as opposed to the 4 bytes of
the previous case.
p_array[0] p_array[1]
x y z x y z
0
1
2
3
4
5
6
For information on calling unions from C++, see the OS/390 C/C++ Programming
Guide. For information on structure alignment, see Alignment of Structures on
page 114 and Alignment of Nested Structures on page 114. For information how to
use the #pragma pack directive to change alignment, see pack on page 266.
Examples:
In a header file, file.h:
#pragma pack(packed)
struct jeff{
float bill;
int *chris;
}
#pragma pack(reset)
*/
.
.
.
120
Type Specifiers
struct dor{
double stephen;
long alex;
}
Related Information:
v Declarators
v Initializers on page 129
v Structures on page 107
v Dot Operator (.) on page 142
v Arrow Operator (>) on page 142
Incomplete Types
Incomplete types are the type void, an array of unknown size, or structure, union,
or enumeration tags that have no member lists. For example, the following are
incomplete types:
void *incomplete_ptr;
struct dimension linear; /* no previous definition of dimension */
In the preceding example, void is an incomplete type that you cannot complete.
You must complete structure or union and enumeration tags before using them to
declare an object. You can, however, define a pointer to an incomplete structure or
union.
Related Information:
v void Type on page 100
v Arrays on page 101
v Structures on page 107
v Unions on page 114
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.
A declarator has the form:
%%
'
*
identifier
( declarator )
%&
( )
' subscript_declarator
subdeclarator
qualifier
' *
subdeclarator:
Chapter 5. Declarations
121
Declarators
identifier
( subdeclarator )
subscript_declarator
identifier
( subdeclarator )
'
volatile
const
%&
subscript_declarator
constant_expression
%&
' [
constant_expression ]
The data object initial has the storage class auto and the data type char.
You can define or declare a structure, union, or array. Use a declarator that
contains an identifier which names the data object, and some combination of
symbols and identifiers which describe the type of data that the object represents.
The following declaration uses compute[5] as the declarator:
extern long int compute[5];
122
Declarators
exception occurs. OS/390 C/C++ reads volatile objects from memory each time it
needs their value, and writes back to memory each time they are changed.
The volatile qualifier is useful for data objects that have values that can change in
ways unknown to your program (such as the system clock). Do not change or move
portions of an expression that reference volatile objects.
The const qualifier explicitly declares a data object as a data item that you cannot
change. OS/390 C/C++ sets its value at initialization. You cannot use const data
objects in expressions that require a modifiable lvalue. For example, a const data
object cannot appear on the left side of an assignment statement. (An lvalue is an
expression whose address you can take; you can examine or change the object
that the lvalue represents. For more information on lvalues, see lvalues on
page 136.)
These type qualifiers are only meaningful in expressions that are lvalues.
For a volatile or const pointer, you must put the keyword between the * and the
identifier. For example:
int * volatile x;
int * const y = &z;
For a pointer to a volatile or const data object, the type specifier, qualifier, and
storage class specifier can be in any order. For example:
volatile int *x;
*/
*/
*/
*/
or
or
int const *y;
In the following example, the pointer to y is a constant. You can change the value
that y points to, but you cannot change the value of y:
int * const y
In the following example, the value to which y points is a constant integer and you
cannot change it. However, you can change the value of y:
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;
int limit;
char code;
} volatile group;
Chapter 5. Declarations
123
Declarators
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];
} beluga;
The keywords volatile and 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 C++ member
function. You can define or declare any function to return a pointer to a volatile or
const function.
You can put more than one qualifier on a declaration, but you cannot specify the
same qualifier more than once on a declaration.
124
Declarators
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. See Pragma Directives (#pragma) on page 238 for more information on
#pragma pack.
Use the __cdecl keyword to set linkage conventions for function calls in C++
applications. You can use the __cdecl linkage keyword at any language level. The
__cdecl keyword instructs the compiler to read and write a parameter list by using
C linkage conventions.
To set the __cdecl calling convention for a function, place the linkage keyword
immediately before the function name or at the beginning of the declarator. For
example:
void __cdecl f();
char (__cdecl *fp) (void);
OS/390 C/C++ allows the __cdecl keyword on member functions and nonmember
functions. These functions can be static or non-static. It also allows the keyword on
pointer-to-member function types and the typedef specifier.
Note: The compiler accepts both _cdecl and __cdecl (both single and double
underscore).
Following is an example:
// C++ nonmember functions
void __cdecl f1();
static void __cdecl f2();
// pointer to member function type
char (__cdecl *A::mfp) (void);
// typedef
typedef void (* _cdecl void_fcn)(int);
// C++ member functions
class A {
public:
void __cdecl func();
static void __cdecl func1();
}
// Template member functions
template <class T> X {
public:
void __cdecl func();
static void __cdecl func1();
}
// Template functions
template <class T> T __cdecl foo(T i) {return i+1;}
template <class T> T static _cdecl foo2(T i) {return i+1;}
Chapter 5. Declarations
125
Declarators
void __cdecl foo(int);
void __cdecl foo(char);
void foo(int(*)());
void foo(int (__cdecl *)());
extern "C++" {
void __cdecl foo(int);
}
extern "C" {
void __cdecl foo(int);
}
If the function is redeclared, the linkage keyword must appear in the first
declaration, otherwise OS/390 issues an error diagnostic. Following are two
examples:
int c_cf();
int __cdecl c_cf();
int __cdecl c_cf();
int c_cf();
extern "C" {
void CALLC(void (__cdecl *pp)()); // declare an extern C function
}
// accepting a __cdecl function
// pointer
void main() {
p1 = callcxx;
CALLC(p1);
}
126
Declarators
Example 2
/*--------------------------------------------------------------------*/
/* C source file
*/
/*--------------------------------------------------------------------*/
/*
*/
/* C Routine: receiving a function pointer with C linkage
*/
/*
*/
#include <stdio.h>
extern void CALLC(void (*pp)()){
printf(" I am a C function\n");
(*pp)();
// call the function passed in
}
_Export Keyword
Use the _Export keyword (in C++ applications only) with a function name or
external variable to declare that it is be exported (made available to other modules).
For example:
int _Export anthony(float);
The above statement exports the function anthony, if you define the function within
the compilation unit. You must define the function in the same compilation unit in
which you use the _Export keyword.
OS/390 C/C++ allows _Export only at file scope. You cannot use it in a typedef. You
cannot apply the _Export keyword to the return type of a function. For example, the
following declaration causes an error :
_Export int * a(); // error
The _Export keyword must immediately precede the function or object name. If the
_Export keyword is repeated in a declaration, OS/390 C/C++ issues a warning
when you specify the info(gen) option.
Since _Export is part of the declarator, it affects only the closest identifier. In the
following declaration, _Export only modifies a:
int _Export a, b;
In addition, you need to specify the exact identifier that you want exported. For
example, #pragma export(f(int)) would export void f(int) for the above
example.
Chapter 5. Declarations
127
Declarators
To export member functions, you may apply the _Export keyword to the function
declaration, but the function definition must not be inlined. For example:
class X {
public:
...
void _Export Print();
...
};
void X::Print() {
...
}
The above examples demonstrate that you can either export specific members of a
class or the entire class itself. Note that the _Export keyword can be applied to
class tags in nested class declarations.
The function main() cannot be exported. For a description of #pragma export, see
export on page 248.
For more information on using DLLs and exporting functions, see the OS/390
C/C++ Programming Guide.
Example Declarators
The following table describes some declarators:
128
Description
int owner
int *node
int names[126]
int *action( )
volatile int min
int * volatile volume
Declarators
Table 8. Example Declarators (continued)
Example
Description
volatile int * next
volatile int * sequence[5]
Related Information:
v Enumerations on page 91
v Pointers on page 95
v Arrays on page 101
v Structures on page 107
v Unions on page 114
Initializers
An initializer is an optional part of a data declaration that specifies an initial value of
a data object.
An initializer has the form:
,
%%
(
=
' expression
expression
,
{
%&
' expression
,
,
' { '
expression
For unions, structures, and aggregate classes, the set of initial expressions must be
enclosed in brace brackets ({ }) unless the initializer is a string literal. Aggregate
classes refer to classes with no constructors, base classes, virtual functions, or
private or protected members.
Chapter 5. Declarations
129
Initializers
If the initializer of a character string is a string literal, the brace brackets are
optional. You must separate individual expressions by using commas. You can
enclose groups of expressions in braces and separate them by using commas.
In an array, structure, or union that you have initialized using a brace-enclosed
initializer list, OS/390 C/C++ implicitly initializes any members or subscripts that are
not initialized to zero of the appropriate data type.
The section for the data type describes the initialization properties of each data
type.
C++ Notes:
1. You can use an initializer of the form (expression) to initialize fundamental
types in C++. For example, the following two initializations are identical:
int group = 3;
int group(3);
2. You can also use the (expression) form to initialize C++ classes. See
Initialization by Constructor on page 327 for more information on initializing
classes.
3. You can initialize variables at file scope with nonconstant expressions. ANSI/ISO
C does not allow this.
4. 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;
int i = 3;
skiplabel: i = 4;
5. You can initialize classes in external, static, and automatic definitions. The
initializer contains an equal sign (=) that is followed by a brace-enclosed,
comma-separated, list of values. You do not need to initialize all members of a
class.
The following example explicitly initializes the first eight elements of the array grid.
The remaining four elements that are not explicitly initialized are initialized as if they
were explicitly initialized to zero.
static short grid[3] [4] = {0, 0, 0, 1, 0, 0, 1, 1};
[0]
[1]
[2]
[3]
[0]
[1]
Value
Element
0
0
0
1
0
0
grid[1]
grid[1]
grid[2]
grid[2]
grid[2]
grid[2]
Related Information
v
v
v
v
v
v
130
Value
[2]
[3]
[0]
[1]
[2]
[3]
1
1
0
0
0
0
Initializers
v
v
v
v
C++ References
A C++ reference is an alias or an alternative name for an object. All operations that
are applied to a reference act on the object the reference refers to. The address of
a reference is the address of the aliased object.
You can define a reference type by placing the & after the type specifier. You must
initialize all references except function parameters when you define them.
Because you pass arguments of a function 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, you must pass the argument by reference. This is as opposed to
being passed by value. You can pass arguments by reference by using either
references or pointers. In C++, this is transparent. Unlike C, C++ does not force you
to use pointers if you want to pass arguments by reference. For example:
Chapter 5. Declarations
131
C++ References
int f(int&);
void main()
{
extern int i;
f(i);
}
You cannot tell from the function call f(i) that it is passing the argument by
reference.
You cannot refer to NULL.
Initializing References
The object that you use to initialize a reference must be of the same type as the
reference. Otherwise, it must be of a type that is convertible to the reference type. If
you initialize a reference to a constant by using an object that requires conversion,
you create a temporary object. The following example creates a temporary object of
type float:
int i;
const float& f = i; // reference to a constant float
//
//
//
//
//
valid
error, two definitions of RefOne
assign num2 to num1
error, uninitialized reference
valid
Related Information
v
v
v
v
v
132
Because the above example does not specify the order of subexpression
evaluation, you can explicitly force the grouping of operands with operators by using
parentheses.
In the following expression, the * and / operations are performed before + because
of precedence. In addition, b is multiplied by c before it is divided by d because of
associativity:
a + b * c / d
Copyright IBM Corp. 1996, 2000
133
Associativity
Operators
left to right
::
Primary
left to right
()
Unary
right to left
++ -- + - !
& *
(type_name) sizeof new
delete digitsof2
precisionof2
C++ Pointer-to-Member
left to right
.* >*
Multiplicative
left to right
Additive
left to right
Bitwise Shift
left to right
<<
Relational
left to right
<
Equality
left to right
==
left to right
&
Bitwise Exclusive OR
left to right
| or
Bitwise Inclusive OR
left to right
Logical AND
left to right
&&
Logical OR
left to right
||
Conditional
right to left
? :
Assignment
right to left
= += -= *= /= <<=
>>= %= &= |= |=
Comma
left to right
[ ]
->
%
>>
>
<=
>=
!=
Do not specify the order of evaluation for function call arguments or for the
operands of binary operators. Avoid writing ambiguous expressions such as:
z = (x * ++y) / func1(y);
func2(++i, x[i]);
In the example above, all C language implementations may not evaluate ++y and
func1(y) in the same order. If y had the value of 1 before the first statement, you
will not know whether or not the value of 1 or 2 is passed to func1(). In the second
statement, if i had the value of 1, you will not know whether the first or second
array element of x[ ] is passed as the second argument to func2().
The example does not specify the order of grouping operands with operators in an
expression that contains more than one instance of an operator with both
associative and commutative properties. The operators that have the same
2. C only
134
The above example does not specify the order of grouping operands with operators
that are both associative and commutative. Consequently, the compiler can group
the operands and operators in the following expression:
total = price + prov_tax + city_tax;
If the values in this expression are integers, the grouping of operands and operators
does not affect the result. Because intermediate values are rounded, different
groupings of floating-point operators may give different results.
In certain expressions, the grouping of operands and operators can affect the result.
For example, in the following expression, each function call might be modifying the
same global variables.
a = b() + c() + d();
This expression can give different results that depend on the order in which the
functions are called.
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();
Operands
Most expressions can contain several different, but related, types of operands. The
following type classes describe related types of operands:
Integral
Arithmetic
135
Operands
Scalar
Aggregate
Many operators cause conversions from one data type to another. Chapter 7.
Implicit Type Conversions on page 167 discusses conversions.
lvalues
An lvalue is an expression whose address you can take. You can examine or
change the object that the lvalue represents. A modifiable lvalue is an expression
that represents an object that you can change. It is typically the left operand in an
assignment expression. For example, array names and const objects are not
modifiable lvalues, but static int objects are.
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 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
Expression
lvalue
x = 42;
*ptr = newvalue;
*ptr
a++
Type-based Aliasing
The compiler follows the type-based aliasing rule in the ANSI C standard when the
ANSIALIAS option is in effect. This rule states that a pointer can only be
dereferenced to an object of the same type. 3 The common coding practice of
136
lvalue
casting a pointer to a different type and then dereferencing it violates this rule. Note
that char pointers are an exception to this rule. Refer to the description of the
ANSIALIAS option in OS/390 C/C++ Users Guide for additional information.
The compiler uses the type-based aliasing information to perform optimizations to
the generated code. Contravening the type-based aliasing rule can lead to
unexpected behavior, as demonstrated in the following example:
int *p;
double d = 0.0;
int *faa(double *g);
/* cast operator */
void foo(double f) {
p = faa(&f);
/* turning &f into a int ptr */
f += 1.0;
/* compiler may purge this statement */
printf("f=%x\n", *p);
}
int *faa(double *g) { return (int*) g; }
/* questionable cast; */
/* the function can be
in another compile unit */
void main() {
foo(0.0);
}
In the above printf statement, *p can not be dereferenced to a double under the
ANSI aliasing rule. The compiler determines that the result of f += 1.0; is never
used subsequently. Thus, the optimizer may purge the statement from the
generated code. If you compile the above example with the OPTIMIZE and ANSIALIAS
options, the printf statement may output 0 (zero).
Related Information
v
v
v
v
Primary Expressions
A primary expression can be:
v An identifier
v A qualified class name
v A string literal
v A parenthesized expression
v A constant expression
v A function call
v An array element specification
v A structure or union member specification
All primary operators have the same precedence and have left-to-right associativity.
137
Primary Expressions
You can use the class scope operator to qualify class names or class member
names. You can use a hidden class member name by qualifying it with its class
name and the class scope operator. Whenever you follow a class name by a ::
operator, OS/390 C/C++ interprets the name as a class name.
In the following example, the declaration of the variable X hides the class type X.
However, you can still use the static class member count by qualifying it with the
class type X and the scope resolution operator.
#include <iostream.h>
class X
{
public:
static int count;
};
int X::count = 10;
void main ()
{
int X = 0;
cout << X::count << endl;
}
The scope resolution operator is also discussed in Class Names on page 279 and
in Scope of Class Names on page 282.
Parenthesized Expressions ( )
Use parentheses to explicitly force the order of expression evaluation. The following
expression does not contain any parentheses that are used for grouping operands
and operators. The parentheses that surround weight, zipcode form a function call.
Note how the compiler groups the operands and operators in the expression
according to the rules for operator precedence and associativity:
-discount * item + handling(weight, zipcode) < .10 * item
138
Primary Expressions
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);
Constant Expressions
A constant expression is an expression with a value that may be determined during
compilation. It cannot be changed at runtime, it can only be evaluated. You can
compose a constant expression with the following:
v Integer constants
v Character constants
v Floating-point constants
v Enumeration constants
v Address constants
v Other constant expressions
Some constant expressions, such as string literals or address constants, are
lvalues.
The C and C++ languages require integral constant expressions in the following
places:
v In the subscript declarator, as the description of an array bound
v After the keyword case in a switch statement
v In an enumerator, as the numeric value of an enum constant
v In a bit-field width specifier
v In the preprocessor #if statement (enumeration constants, address constants,
and sizeof cannot be specified in the preprocessor #if statement.)
v In the initializer of a file scope data definition.
In all these contexts, 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. You can initialize function-scope
static and extern declarations.
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. The constant expression in
the initializer can contain the following:
v integer, character, enumeration, and float constants
v casts to any type
v sizeof expressions
v unary address expressions (static objects only)
OS/390 C/C++ does not allow functions, class objects, pointers, and references
unless they occur in sizeof expressions. Comma operators and assignment
operators cannot appear in constant expressions.
Constant
x = 42;
extern int cost = 1000;
y = 3 * 29;
42
1000
3 * 29
139
Primary Expressions
Function Calls ( )
A function call is a primary expression that contains a simple type name and a
parenthesized argument list. The argument list can contain any number of
expressions that are separated by commas. It can also be empty.
For example:
stub()
overdue(account, date, amount)
notify(name, date + 5)
report(error, time, date, ++num)
OS/390 C/C++ evaluates the arguments, and initializes each formal parameter with
the value of the corresponding argument. The semantics of argument passing are
identical to those of assignments. Assigning a value to a formal parameter within
the function body changes the value of the parameter within the function, but has
no effect on the argument.
The type of a function call expression is the return type of the function. The return
statement in the function definition determines the return value. The result of a
function call is an lvalue only if the function returns a reference. A function can call
itself.
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 on page 95.)
OS/390 C/C++ converts arguments that are arrays and functions to pointers before
passing them as function arguments.
Arguments passed to nonprototyped C functions undergo conversions. OS/390
C/C++ converts short or char parameters to int, and float parameters to double.
Use a cast expression for other conversions. (See Cast Expressions on page 146
for more information.)
An implicit declaration of extern int func(); is assumed. Consequently, in C only,
if a function definition has external linkage and a return type of int, you can make
calls to the function before you explicitly declare it. This is not true in C++.
The compiler compares the data types that are provided by the calling function with
the data types that the called function expects. The compiler also performs type
conversions if the declaration of the function is either:
v In function prototype format and the parameters differ from the prototype
OR
v Visible at the point where you call the function.
For example, the declaration of funct is a prototype. When you call function funct,
OS/390 C/C++ converts parameter f to a double, and parameter c to an int:
char * funct (double d, int i);
/* ... */
void main(void)
{
float f;
char c;
funct(f, c) /* f is a double, c is an int */
}
140
Primary Expressions
The order in which parameters are evaluated is not specified. Avoid such calls as:
method(sample1, batch.process--, batch.process);
In this example, the compiler may evaluate batch.process-- last, causing the last
two arguments to be passed with the same value.
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.
CBC3X06C
/**
** This example illustrates function calls
**/
#include <stdio.h>
void func (int a, int b);
int main(void)
{
int x = 5, y = 7;
func(x, y);
printf("In main, x = %d
}
return(0);
y = %d\n", x, y);
b = %d\n", a, b);
b = 7
y = 7
141
Primary Expressions
for (first = 0; first <= 3; ++first)
for (second = 0; second <= 2; ++second)
for (third = 0; third <= 5; ++third)
code[first][second][third] = 100;
The primary expression must be an object of type class, struct, or union. The
name must be a member of that 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 Chapter 12. C++ Class Members and
Friends on page 287. See also Unions on page 114 and Structures on page 107.
Unary Expressions
A unary expression contains one operand and a unary operator. All unary operators
have the same precedence and have right-to-left associativity.
142
Unary Expressions
As indicated in the following descriptions, you can perform the usual arithmetic
conversions on the operands of most unary expressions. See Arithmetic
Conversions on page 170 for more information.
The following table summarizes the operators for unary expressions:
Increment (++)
Unary Minus (-)
Address (&)
sizeof
new
Decrement (--)
Logical Negation (!)
Indirection (*)
digitsof
delete
Increment (++)
The increment operator (++) adds 1 to the value of an operand. If the operand is a
pointer, it increments the operand by the size of the object to which it points. The
operand receives the result of the increment operation. The operand must be a
modifiable lvalue of arithmetic or pointer type.
You can put the ++ before or after the operand. If it appears before the operand,
OS/390 C/C++ increments the operand, and uses the incremented value in the
expression. If you put the ++ after the operand, OS/390 C/C++ uses the value of the
operand in the expression before it increments the operand. For example:
play = ++play1 + play2++;
C++ Note: C++ distinguishes between prefix and postfix forms of the increment
operator: The result of a C++ postfix increment has the same type as
the operand, except for possible integral promotion, but is not an lvalue.
The result of a C++ prefix increment has the same type as the operand,
except for possible integral promotion, and is an lvalue. The C language
makes no such distinction. The result in C has the same type as the
operand, except for possible integral promotion, but is not an lvalue.
You can perform the usual arithmetic conversions on the operand. See Arithmetic
Conversions on page 170.
Decrement ()
The decrement operator (--) subtracts 1 from the value of an operand. If the
operand is a pointer, it decreases the operand by the size of the object to which it
points. The operand receives the result of the decrement operation. The operand
must be a modifiable lvalue.
You can put the decrement operator before or after the operand. If it appears before
the operand, OS/390 C/C++ decrements the operand, and uses the decremented
value 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--;
143
Unary Expressions
is equivalent to the following three expressions:
play1 = play1 - 1;
play = play1 + play2;
play2 = play2 - 1;
C++ Note: C++ distinguishes between prefix and postfix forms of the decrement
operator. The result of a C++ postfix decrement has the same type as
the operand, except for possible integral promotion, but is not an lvalue.
The result of a C++ prefix decrement has the same type as the
operand, except for possible integral promotion, and is an lvalue. The C
language makes no such distinction. The result in C has the same type
as the operand, except for possible integral promotion, but is not an
lvalue.
OS/390 C/C++ performs the usual arithmetic conversions on the operand. See
Arithmetic Conversions on page 170.
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 has the same type as the operand, except for possible integral
promotion.
Note: Any minus sign in front of a constant is not part of the constant.
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.
144
Unary Expressions
Suppose a short integer x represents the decimal value 5. The 16-bit binary
representation of x is:
0000000000000101
The expression x yields the following result (that is represented here as a 16-bit
binary number):
1111111111111010
Note that you can represent the character by the trigraph ??-.
The 16-bit binary representation of 0 is:
1111111111111111
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 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 that has 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. It has the same type as the member. The result is not
an lvalue.
Suppose you define p_to_y as a pointer to an int, and you define y as an int. The
following expression assigns the address of the variable y to the pointer p_to_y:
p_to_y = &y;
Indirection (*)
The indirection operator (*) determines the value to which the pointer-type operand
points.
The operand cannot be a pointer to an incomplete type. The operation yields an
lvalue or a function designator if the operand points to a function. OS/390 C/C++
converts arrays and functions to pointers.
The type of the operand determines the type of the result. For example, 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 is not defined.
Suppose you define p_to_y as a pointer to an int, and you define y as an int.
Then, following the expressions cause the variable y to receive the value 3:
145
Unary Expressions
p_to_y = &y;
*p_to_y = 3;
Cast Expressions
Use the cast operator 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.
A cast to a fixed-point decimal type too small to hold the value discards high-order
digits without an overflow exception. If the number of digits is even, it also clears
the pad digit while an implicit conversion does not. For example, in decimal(4) x =
12345d, y = (decimal(4)) 12345d; the storage for x actually contains 12345d while
the storage for y contains 02345d.
|
|
|
|
|
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, you can cast
it to any type for which the class has a user-defined conversion function.
Conversion Functions on page 326 describes user-defined 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, OS/390 C/C++ does not perform user-defined
conversions, and the result is an lvalue.
There are two types of casts that take one argument:
v C-style casts, with the format (X)a. Both C and C++ allow these casts.
v function-style casts with one argument, such as X(a). Only C++ allows these
casts.
Both types of casts convert the argument a to the type X. In C++, 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.
v For more information on implicit conversions that use constructors, see
Conversion by Constructor on page 326.
v You can also do explicit conversions using conversion functions. For more
information, see Conversion Functions on page 326.
v Standard Type Conversions on page 167 describes implicit conversions using
standard types.
146
Unary Expressions
The operand can be the parenthesized name of a type or an expression.
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 the end of program runtime:
#include <stdio.h>
int main(void){
int b = 5;
sizeof(b++);
return(0);
}
Except in preprocessor directives, you can use a sizeof expression wherever you
require an integral constant. A very common use for the sizeof operator is to
determine the size of objects that are referred to during storage allocation, input,
and output functions.
Another use of sizeof is in porting code across platforms. You should use the
sizeofoperator to determine the size that a data type represents, for example:
sizeof(int);
Using the sizeof operator with decimal(n,p) results in the total number of bytes
that are occupied by the decimal type. OS/390 C/C++ implements decimal data
types using the native packed decimal format. Each digit occupies half a byte. The
sign occupies an additional half byte. The following example gives you a result of 6
bytes:
sizeof(decimal(10,2));
C++ Notes: The result of a sizeof expression depends on the type to which it is
applied:
An array
A class
147
Unary Expressions
equal to the number of bytes in an
object of that class including any
padding required for placing class
objects in an array.
A reference
The results of the digitsof and precisionof operators are integer constants. See
Fixed-Point Decimal Constants (C Only) on page 65 and Fixed-Point Decimal
Data Types (C Only) on page 89 for more information about decimal types.
::
new
( argument_list )
( type )
new_type
initial_value )
%&
If you prefix new with the scope resolution operator (::), your program uses the
global operator new(). If you specify an argument_list, your program uses the
overloaded new operator that corresponds to that argument_list. The type is an
existing built-in or user-defined type. A new_type is a type that you have not already
defined. It can include type specifiers and declarators.
Use an allocation expression that contains the new operator to find storage in free
store for the object you are creating. The new expression returns a pointer to the
object created. You can use it to initialize the object. If the object is an array, it
returns a pointer to the initial element.
You can use the routine set_new_handler() to change the default behavior of new.
See set_new_handler() Set Behavior for new Failure on page 150 for more
information.
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.
148
Unary Expressions
When the created object 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 you are using an existing
type. You can create an array with zero bounds with the new operator. The following
example returns a pointer to a unique object:
char * c = new char[0];
An object created with operator new() or operator new[]() exists until the program
ends, or you call the operator delete() or operator delete[](). These calls
destroy the objects and deallocate the memory pointed to.
If you use parentheses within a new_type, they should also surround the new_type
to prevent syntax errors. In the following example, OS/390 C++ allocates storage
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()
}
The type of the created object cannot contain class declarations, enumeration
declarations, or const or volatile types. It can contain pointers to const or
volatile objects.
For example, you can use const char*, but not char* const.
You can supply additional arguments to new by using the argument_list, also called
the placement syntax. If you use placement arguments, a declaration of operator
new() or operator new[]() with these arguments must exist. For example:
#include <stddef.h>
class X
{
public:
void* operator new(size_t,int, int){ /* ... */ }
};
//
.
//
.
//
.
void main ()
{
X* ptr = new(1,2) X;
}
For more information on the class member operator new() and operator new[]()
function, see Overloaded new and delete on page 316 and Free Store on
page 322. For more information on constructing and destructing class objects with
new and delete, see Constructors and Destructors Overview on page 317.
Chapter 6. Expressions and Operators
149
Unary Expressions
When an object of a class type is created with the new operator, the member
operator new() function (for objects that are not arrays) or the member operator
new[]() function (for arrays of any number of dimensions) is implicitly called. The
first argument is the amount of space requested.
The following rules determine the storage allocation function that OS/390 C++ uses:
1. If your own operator new[]() exists, the object is an array, and it does not use
the :: (scope resolution) operator, OS/390 C++ uses your operator new[]().
2. If you have not defined an operator new[]() function, the global ::operator
new[]() function defined in <new.h> is used. The allocation expression of the
form ::operator new[]() ensures that the global new operator is called, rather
than your class member operator.
3. If your own operator new() exists, and the object is not an array, and the ::
operator is not used, your operator new() is used.
4. If you have not defined an operator new() function, the global ::operator
new() function defined in <new.h> is used. The allocation expression of the form
::operator new() ensures that the global new operator is called, rather than
your class member operator.
When a nonclass object is created with the new operator, the global ::operator
new() is used.
The order of evaluation of a call to an operator new() is undefined in the evaluation
of arguments to constructors. If operator new() returns 0, the arguments to a
constructor may or may not have been evaluated.
You can initialize objects that are 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, you must provide the new initializer when you allocate
any object of that class. 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. OS/390 C++ calls the constructor
to initialize each array element (class object).
Initialization using the new initializer is performed only if new successfully allocates
storage.
For more information on the class member operator new() and operator new[]()
function, see Overloaded new and delete on page 316 in Special Overloaded
Operators, and Free Store on page 322. For more information on constructing and
destructing class objects with new and delete, see Constructors and Destructors
Overview on page 317.
When the new operator creates a new object, it calls the operator new() or
operator new[]() function to obtain the needed storage.
150
Unary Expressions
When new cannot allocate storage to create a new object, it calls a new handler
function if one has been installed by a call to set_new_handler(). The
set_new_handler() function is defined in <new.h>. Use it to call a new handler you
have defined or the default new handler.
The set_new_handler() function has the prototype:
typedef void(*PNH)();
PNH set_new_handler(PNH);
If the program fails because new cannot allocate storage, the program exits with the
message:
Operator new failed: no storage is available.
::
delete object_pointer
%&
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. However, 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 operator frees storage allocated for individual objects created with new.
It has the syntax:
151
Unary Expressions
%%
::
delete [ ] array
%&
Binary Expressions
A binary expression contains two operands that are separated by one operator.
Not all binary operators have the same precedence. The table in the section
Operator Precedence and Associativity on page 133 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. To ensure correct results, avoid creating binary expressions that depend
on the order in which the compiler evaluates the operands.
152
Binary Expressions
As indicated in the following descriptions, OS/390 C++ performs the usual
arithmetic conversions on the operands of most binary expressions. See Arithmetic
Conversions on page 170 for more information.
The following table summarizes the operators for binary expressions:
Multiplication (*)
Addition (+)
Relational (< > <= >=)
Bitwise Exclusive OR (|)
Logical OR (||)
Division (/)
Subtraction (-)
Equality (== !=)
Bitwise Inclusive OR (|)
Pointer-to-Member (.* >*)
Remainder (%)
Bitwise Shifts (<< >>)
Bitwise AND (&)
Logical AND (&&)
Multiplication (*)
The multiplication operator (*) yields the product of its operands. The operands
must have an arithmetic type. The result is not an lvalue. OS/390 C/C++ performs
the usual arithmetic conversions on the operands. See Arithmetic Conversions on
page 170.
Because the multiplication operator has both associative and commutative
properties, the compiler can rearrange the operands in an expression that contains
more than one multiplication operator. Consider the following example:
sites * number * cost
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,
OS/390 C/C++ ignores the remainder. For example, expression 7 / 4 yields the
value 1 (rather than 1.75 or 2). On all IBM C and C++ compilers, if either operand is
negative, the result is rounded towards zero.
The result is undefined if the second operand evaluates to 0.
OS/390 C/C++ performs the usual arithmetic conversions on the operands. See
Arithmetic Conversions on page 170.
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;
The sign of the remainder is the same as the sign of the quotient.
Chapter 6. Expressions and Operators
153
Binary Expressions
The usual arithmetic conversions on the operands are performed. See Arithmetic
Conversions on page 170.
Addition (+)
The addition operator (+) yields the sum of its operands. Both operands must have
an arithmetic type, or one 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, OS/390 C/C++ performs the usual
arithmetic conversions on the operands. The result has the type produced by the
conversions on the operands and is not an lvalue.
You can add a pointer to an object in an array to a value that has integral type. The
result is a pointer of the same type as the pointer operand. The result refers to
another element in the array, offset from the original element by the amount that is
specified by the integral value. If the resulting pointer points to storage that is
outside the array, other than the first location outside the array, the result is
undefined. The compiler does not check the boundary of the pointers. For example,
after the addition, ptr points to the third element of the array:
int array[5];
int *ptr;
ptr = array + 2;
See Pointer Conversions on page 168 and Pointer Arithmetic on page 98 for
more information about expressions that contain pointers.
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. You cannot
subtract a pointer from an integral value.
When both operands have an arithmetic type, OS/390 C/C++ performs the usual
arithmetic conversions on the operands. 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.
See Pointer Conversions on page 168 and Pointer Arithmetic on page 98 for
more information about expressions that contains pointers.
154
Binary Expressions
Table 9. Bitwise Shift Operators
Operator
Usage
<<
>>
Each operand must have an integral type. The compiler performs integral
promotions on operands with integral type. Then it converts the right operand to
type int. The result has the same type as the left operand (after the arithmetic
conversions).
The right operand should not have a negative value or a value that is greater than
or equal to the width in bits of the expression being shifted. The result of bitwise
shifts on such values is unpredictable.
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 left_op has the value
4019, the bit pattern (in 16-bit format) of left_op is:
0000111110110011
Result of >>
unsigned type
Nonnegative signed
type
The integral part of the quotient of the left operand divided by the
quantity 2, raised to the power of the right operand. The vacated bits
of a signed value are filled with a copy of the sign bit of the
unshifted value.
The language does not specify how the vacated bits produced by
the >> operator are filled.
155
Binary Expressions
The following table describes the four relational operators:
Table 10. Relational Operators
Operator
Usage
<
>
<=
>=
Both operands must have arithmetic types or be pointers to the same type. The
result has type int.
If the operands have arithmetic types, OS/390 C/C++ performs the usual arithmetic
conversions on the operands.
When the operands are pointers, the locations of the objects to which the pointer
refer determine the result. If the pointers do not refer to objects in the same array,
the result is not defined.
You can compare a pointer to a constant expression that evaluates to 0. You can
also compare a pointer to a pointer of type void*. OS/390 C/C++ converts the
pointer to a pointer of type void*.
If two pointers refer to the same object, you can consider them to be equal. 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 addresses of members
of the same object with relational operators.
|
|
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.
156
Binary Expressions
The following table describes the two equality operators:
Table 11. 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, OS/390 C/C++ performs the usual arithmetic
conversions on the operands.
If the operands are pointers, the locations of the objects to which the pointers refer
determines the result.
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. The !=
operator evaluates to true if the pointer operand does not evaluate 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. The following expressions
contain examples of equality and relational operators:
time < max_time == status < complete
letter != EOF
Note: Do not confuse the equality operator (==) with the assignment (=) operator.
For example:
if(x == 3)
if(x = 3)
157
Binary Expressions
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
bit pattern of b
bit pattern of a & b
0000000001011100
0000000000101110
0000000000001100
Note: Do not confuse the bitwise AND (&) operator with the logical AND (&&)
operator. For example,
1 & 4 evaluates to 0
while
1 && 4 evaluates to 1
0000000001011100
0000000000101110
0000000001110010
Note: The bitwise exclusive OR may appear as a on your screen. For more
information on these symbols, refer to the OS/390 C/C++ Programming
Guide.
158
Binary Expressions
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
bit pattern of b
bit pattern of a | b
0000000001011100
0000000000101110
0000000001111110
Note:
v The bitwise OR may appear as a on your screen. For more information
on these symbols, refer to the OS/390 C/C++ Programming Guide.
v Do not confuse the bitwise OR (|) operator with the logical OR (||)
operator. For example,
1 |
4 evaluates to 5
while
1 || 4 evaluates to 1
Result
1 && 0
1 && 4
0 && 0
0
1
0
The following example uses the logical AND operator to avoid division by zero:
(y != 0) && (x / y)
159
Binary Expressions
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.
Unlike the | (bitwise inclusive OR) operator, the || operator guarantees left-to-right
evaluation of the operands. If the left operand has a nonzero value, OS/390 C/C++
does not evaluate the right operand.
The following examples show how OS/390 C/C++ evaluates expressions that
contain the logical OR operator:
Expression
Result
1 || 0
1 || 4
0 || 0
1
1
0
OS/390 C/C++ does not evaluate the expression ++y when the expression ++x
evaluates to a nonzero quantity.
Note: The logical OR may appear as a on your screen. For more information on
these symbols, refer to the OS/390 C/C++ Programming Guide.
Note: Do not confuse the logical OR (||) with the bitwise OR (|) operator. For
example:
1 || 4 evaluates to 1
while
1 | 4 evaluates to 5
160
Binary Expressions
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
on page 292.
Conditional Expressions
A conditional expression is a compound expression that contains a condition
(operand1), an expression to be evaluated if the condition has a nonzero value
(operand2), and an expression to be evaluated if the condition has the value 0
(operand3).
Conditional expressions have right-to-left associativity. OS/390 C/C++ evaluates the
left operand first, and then evaluates only one of the remaining two operands.
The conditional expression contains one two-part operator. The ? symbol follows the
condition, and the : symbol appears between the two action expressions. OS/390
C/C++ treats all expressions that occur between the ? and : as one expression.
The first operand must have a scalar type. The type of the second and third
operands must be one of the following:
v An arithmetic type
v A compatible pointer, structure, or union type
v void.
The second and third operands can also be a pointer or a null pointer constant.
Two objects are compatible when they have the same type but not necessarily the
same type qualifiers (volatile, or const). Pointer objects are compatible if they
have the same type or are pointers to void.
OS/390 C/C++ evaluates the first operand, and its value determines whether
OS/390 C/C++ evaluates the second or third operand:
v If the value is not equal to 0, it evaluates the second operand.
v If the value is equal to 0, it evaluates the third operand.
The result is the value of the second or third operand.
If the second and third expressions evaluate to arithmetic types, OS/390 C/C++
performs the usual arithmetic conversions on the values. The following tables show
how the types of the second and third operands determine the type of the result.
161
Conditional Expressions
Type of Result
Arithmetic
Arithmetic
void
void
void
Pointer to type
Pointer to type
Pointer to object or
incomplete type
Pointer to void
Type of Result
Reference to type
Reference to type
Class T
Class T
Class T
Class T
Class X
throw expression
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');
162
Conditional Expressions
int i,j,k;
(i == 7) ? j ++ : k = j;
That is, k is treated as the third operand, not the entire assignment expression k =
j. The error arises because a conditional expression is not an lvalue, and the
assignment is not valid.
To make the expression evaluate correctly, enclose the last operand in parentheses:
int i,j,k;
(i == 7) ? j ++ : (k = j);
Assignment Expressions
An assignment expression stores a value in the object that is designated by the left
operand. There are two types of assignment operators: simple assignment and
compound assignment.
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.
In C, the result of an assignment expression is not an lvalue. The result of an
assignment expression is an lvalue in C++.
All assignment operators have the same precedence and have right-to-left
associativity.
163
Assignment Expressions
If the left operand is an object of reference type, the assignment is to the object that
is 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. 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, OS/390 C/C++ remaps the layout of
the right operand to match the layout of the left. This remapping of structures might
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 Initializing Pointers on page 96
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. For example:
const int *p1;
int *p2;
p2 = p1; /* this is NOT allowed */
p1 = p2;
/* this IS allowed */
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 (zero) to strangeness, the value
of strangeness to charm, the value of charm to beauty, and the value of beauty to
truth:
truth = beauty = charm = strangeness = 0;
Note: The assignment (=) operator should not be confused with the equality
comparison (==) operator. For example:
if(x == 3)
if(x = 3)
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.
164
Assignment Expressions
The following table shows the operand types of compound assignment expressions:
Operator
Left Operand
Right Operand
+= or -=
Arithmetic
Arithmetic
+= or -=
Pointer
Integral type
*=,/=, and %=
Arithmetic
Arithmetic
Integral type
Integral type
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 that uses each operator:
Operator
Example
Equivalent Expression
+=
index += 2
index = index + 2
-=
*(pointer++) -= 1
*pointer = *(pointer++) - 1
*=
bonus *= increase
/=
time /= hours
%=
allowance %= 1000
<<=
>>=
form >>= 1
&=
mask &= 2
|=
test |= pre_test
|=
flag |= ON
flag = flag | ON
Although the equivalent expression column shows the left operands (from the
example column) that OS/390 C/C++ evaluates twice, OS/390 C/C++ evaluates the
left operand only once.
165
Comma Expression
In the following example, if omega has the value 11, the expression increments delta
and assigns the value 3 to alpha:
alpha = (delta++, omega % 4);
The primary use of the comma operator is to produce side effects in the following
situations:
v Calling a function
v Entering or repeating an iteration loop
v Testing a condition
v Other situations where you require a side effect, but not the immediate result of
the expression
To use the comma operator in a context where the comma has other meanings,
such as in a list of function arguments or a list of initializers, you must enclose the
comma operator in parentheses. For example, the following function has only three
arguments: the value of a, the value 5, and the value of c.
f(a, (t = 3, t + 2), c);
The value of the second argument is the result of the comma expression in
parentheses, which has the value 5:
t = 3, t + 2
The following table gives some examples of the uses of the comma operator:
166
Statement
Effects
Integral Promotions
You can use certain fundamental types wherever you can use an integer. You can
convert the following fundamental types through integral promotion:
v char
v wchar_t
v short int
v enumerators
v objects of enumeration type
v integer bit fields (both signed and unsigned)
Except for wchar_t, if you cannot represent the value by an int, OS/390 C/C++
converts the value to an unsigned int. For wchar_t, if an int can represent all the
values of the original type, OS/390 C/C++ converts the value to the type that can
best represent all the values of the original type. For example, if a long can
represent all the values, the value is converted to a long.
167
Signed-Integer Conversions
The compiler converts a signed integer to a shorter integer. It does this by
truncating the high-order bits and converting the variable to a longer signed integer
by sign-extension.
Conversion of signed integers to floating-point values generally takes place without
loss of information. However, when you convert an int, a long int, or a long long
int value to a float, some precision may be lost. When converting a long long
int type to a float, OS/390 C/C++ rounds to the nearest representable number.
When converting a signed integer to an unsigned integer, OS/390 C/C++ converts
the signed integer to the size of the unsigned integer. It interprets the result as an
unsigned value.
When converting a long long int type to packed decimal, the resulting size is
decimal(20,0).
Unsigned-Integer Conversions
You can convert an unsigned integer to a shorter unsigned or signed integer by
truncating the high-order bits. OS/390 C/C++ converts an unsigned integer to a
longer unsigned or signed integer by zero-extending. Zero-extending pads the
leftmost bits of the longer integer with binary zeros.
When you convert an unsigned integer to a signed integer of the same size, no
change in the bit pattern occurs. However, the value changes if you set the sign bit.
Floating-Point Conversions
If you convert a float value to a double, it undergoes no change in value. If you
convert a double to a float OS/390 C/C++ represents it exactly, if possible. If the
compiler cannot exactly represent the double value as a float, the value loses
precision. If the value is too large to fit into a float, the result is undefined.
When OS/390 C/C++ converts a floating-point value to an integer value, it discards
the decimal fraction portion of the floating-point value in the conversion. If the result
is too large for the given integer type, the result of the conversion is undefined.
Pointer Conversions
OS/390 C/C++ performs pointer conversions when you use pointers. These
conversions include pointer assignment, initialization, and comparison.
You can convert a constant expression that evaluates to zero to a pointer. This
pointer will be a null pointer (pointer with a zero value), and is guaranteed not to
point to any object.
You can convert any pointer to an object that is not a const or volatile object to a
void*. You can also convert any pointer to a function to a void*, provided that a
void* has sufficient bits to hold it.
You can generally convert an expression with type array of some type to a pointer
to the initial element of the array. You cannot do this conversion when the
expression is used as the operand of the & (address) operator or the sizeof
operator.
168
Reference Conversions
A reference conversion can be performed wherever a reference initialization occurs,
including reference initialization done in argument passing and function return
values. You can convert a reference to a class to a reference to an accessible base
class of that class, as long as the conversion is not ambiguous. The result of the
conversion is a reference to the base class subobject of the derived class object.
You can perform reference conversion if OS/390 C/C++ allows the corresponding
pointer conversion.
Pointer-to-Member Conversions
Pointer-to-member conversion can occur when you initialize, assign, or compare
pointers to members.
A constant expression that evaluates to zero converts to a distinct pointer to a
member.
Note: A pointer to a member is not the same as a pointer to an object or a pointer
to a function.
You can convert a pointer to a member of a base class to a pointer to a member of
a derived class, if the following conditions are true:
v The conversion is not ambiguous. The conversion is ambiguous if multiple
instances of the base class are in the derived class.
v You can convert a pointer to the derived class to a pointer to the base class. If
this is the case, the base class is accessible. See Derivation Access of Base
Classes on page 342 for more information.
For more information, see Pointers to Members on page 292 and C++
Pointer-to-Member Operators (.* >*) on page 160.
169
Other Conversions
By definition, the void type has no value. Therefore, you cannot convert it to any
other type. No other value can be converted to void by assignment. However, a
value you can explicitly cast to void.
You cannot convert between structure or union types.
When a fixed point decimal type is converted to an integral type, OS/390 C/C++
discards the fractional part. An explicit conversion to a fixed-point decimal type may
cause an overflow exception. To avoid this, use an explicit cast.
|
|
|
In C, when you define a value by using the enum type specifier, OS/390 C/C++
treats the value as an int. Conversions to and from an enum value proceed as for
the int type.
In C++, you can convert from an enum to any integral type but not from an integral
type to an enum.
There are no standard conversions between class types.
Arithmetic Conversions
Most C++ operators perform type conversions to bring the operands of an
expression to a common type. Or, they extend short values to the integer size used
in OS/390 operations. The conversions 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 standard
conversions are known as the arithmetic conversions because they apply to the
types of values that are ordinarily used in arithmetic.
You can use arithmetic conversions to match the operands of arithmetic operators.
170
Arithmetic Conversions
Arithmetic conversion proceeds in the following order:
Operand Type
Conversion
Note: On OS/390 C/C++, an int type and a long type are the same length, so
unsigned int cannot be represented by a signed long.
171
Arithmetic Conversions
172
Chapter 8. Functions
This chapter describes the structure and use of functions in C and C++. Specifically,
it discusses the following topics:
v Functions Overview
v C++ Enhancements to C Functions
v Function Declarations on page 174
v The main() Function on page 183
v Calling Functions and Passing Arguments on page 184
v Default Arguments in C++ Functions on page 189
v Function Return Values on page 191
v Pointers to Functions on page 192
v C++ Inline Functions on page 194
Related Information
v Member Functions on page 289
v Inline Member Functions on page 290
v Chapter 13. C++ Overloading on page 305
v Chapter 14. Special C++ Member Functions on page 317
v Virtual Functions on page 351
Functions Overview
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. Use the declaration to declare the format and
existence of a function prior to using the function. A function definition contains a
function declaration and the body of the function. A function can only have one
definition.
Both C++ and ANSI/ISO C use the style of declaration that is called prototyping. A
function prototype refers to the return type, name, and argument list components of
a function. The compiler uses the prototype to check argument types and to convert
arguments. Prototypes can appear several times in a program, if the declarations
are compatible. They allow the C compiler to check for mismatches between the
parameters of a function call and those in the function declaration.
C++ Note: C++ functions must use prototypes. Usually, you place them in header
files, while you place function definitions in source files. Only C allows
functions that do not have prototypes.
173
Function Declarations
A function declaration establishes the name and the parameters of the function.
%%
extern
static
linkage_specifier
type_specifier
,
% function_declarator (
'
parameter
const
volatile
%&
C Function Declarations
A function cannot be declared as returning a data object having a volatile or const
type. It can, however, return a pointer to a volatile or const object. Also, a function
cannot return a value that has a type of array or function.
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.
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);
174
Function Declaration
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, you cannot have the class definition 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();
int g()
{
return f();
}
175
Function Declaration
enum subway_line {yonge, university, spadina, bloor};
int subway(char * subway_line, int stations,
enum subway_line intersects);
|
|
|
CBC3RAAV
/**
** This example shows how a function is declared and defined
**/
#include <stdio.h>
double absolute(double);
int main(void)
{
double f = -3.0;
printf("absolute number = %lf\n", absolute(f));
}
return (0);
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. The function main(), declares absolute() with the return type
void.
CBC3RAAW
/**
** This example uses a function with a void return type
**/
#include <stdio.h>
int main(void)
{
void absolute(float);
float f = -8.7;
absolute(f);
}
return(0);
176
Function Declaration
The following code fragments show several function declarations. The first fragment
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(). f1() 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, you can use a typedef 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 example declares an external function f2(). f2() takes a constant
integer as its first argument, and can have variable numbers and types of other
arguments. It returns type int:
int extern f2(const int ...);
Function f3() takes an int argument with a default value. This is the value that is
returned from function f2(), and that has a return type of int:
const int j = 5;
int f3( int x = f2(j) );
See Default Arguments in C++ Functions on page 189 for more information about
default function arguments.
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;
};
See const and volatile Member Functions on page 289 for more information about
constant member functions.
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();
Chapter 8. Functions
177
Function Declaration
Related Information:
v Declarators on page 121
v extern Storage Class Specifier on page 77
Function Definitions
A function definition contains a function declaration and the body of a function. It
specifies the function name, formal parameters, the return type, and storage class
of the function.
%%
extern
static
linkage_specifier
% function_declarator '
type_specifier
parameter_declaration
block_statement
%&
178
Function Definitions
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 if
you do not pass any parameters to it, use the keyword void as the type specifier.
A function can return a pointer or reference to a function, array, or to an object with
a volatile or const type. 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 that has the volatile or const qualifier. (This restriction does not
apply to C++.)
You cannot define an array of functions. You can, however, define an array of
pointers to functions.
In the following example, ary is an array of two function pointers. The example type
casts the values that are assigned to ary for compatibility:
CBC3RAAT
/**
** This example uses an array of pointers to functions
**/
#include <stdio.h>
int func1(void);
void func2(double a);
int main(void)
{
double num;
int retnum;
void (*ary[2]) ();
ary[0] = ((void(*)())func1);
ary[1] = ((void(*)())func2);
retnum=((int (*)())ary[0])();
/* calls func1 */
printf("number returned = %i\n", retnum);
((void (*)(double))ary[1])(num);
/* calls func2 */
}
return(0);
int func1(void)
{
int number=3;
return number;
}
void func2(double a)
{
a=333.3333;
printf("result of func2 = %f\n", a);
}
Chapter 8. Functions
179
Function Definitions
The function sum has external linkage and returns an object that has type int. It has
two parameters of type int that are declared as x, and y. The function body
contains a single statement that returns the sum of x and y.
Function Declarator
A function declarator contains an identifier that names a function, and a contains a
list of the function parameters. You should always use prototype function
declarators because you can check the function parameters with them. C++
functions must have prototype function declarators.
Function Declarator Syntax:
%% declarator (
parameter_declaration_list
,
%&
' identifier
'
storage_class_specifier
type_specifier
type_qualifier
declarator
*
abstract_declarator
%&
...
%% '
( abstract_declarator )
direct_abstract_declarator
%&
direct_abstract_declarator:
abstract_declarator
[
(
constant_expression
parameter_declaration_list
Prototype Function Declarators: You should declare each parameter within the
function declarator. Any calls to the function must pass the same number of
arguments as there are parameters in the declaration.
180
Function Definitions
Nonprototype Function Declarators: You should declare each parameter in a
parameter declaration list following the declarator. If you do not declare a
parameter, it has type int.
The compiler widens char and short parameters to int, and widens float
parameters to double. The compiler performs no type checking between the
argument type and the parameter type for nonprototyped functions. As well, it does
not check to ensure that the number of arguments matches the number of
parameters.
You should declare each value that a function receives 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 that OS/390 C/C++ allows is the register storage
class specifier. It allows any type specifier for a parameter. If you do not specify the
register storage class specifier, the parameter will have the auto storage class
specifier. In C only, if you omit the type specifier and you are not using the
prototype form to define the function, the parameter will have type int, as follows:
int func(i,j)
{
/* i and j have type int
}
*/
For information on how to pass multiple arguments, refer to the sections describing
va_arg, va_end(), and va_end() in OS/390 C/C++ Run-Time Library Reference.
The compiler promotes parameters as needed, but does not check the types of the
variable arguments.
You can declare a function with no arguments in two ways:
int f(void);
// ANSI/ISO C Standard
int f();
// C++ enhancement
// Note: In ANSI/ISO C, this declaration means that
// f may take any number or type or parameters
181
Function Definitions
void f(int);
int g(void);
Function Body
The body of a function is a block statement.
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;
}
The following example contains a function declarator sort with table and length.
The example declares table as a pointer to int, and declares length as type int.
Note that the compiler implicitly converts arrays as parameters to a pointer to the
type.
CBC3RAAU
/**
** This example illustrates function declarators.
** Note that arrays as parameters are implicitly
** converted to a pointer to the type.
**/
#include <stdio.h>
void sort(int table[ ], int length);
int main(void)
{
int table[ ]={1,5,8,4};
int length=4;
printf("length is %d\n",length);
sort(table,length);
}
void sort(int table[ ], int length)
{
int i, j, temp;
182
Function Definitions
The following example illustrates how you can use a typedef identifier in a function
declarator:
typedef struct tm_fmt { int minutes;
int hours;
char am_pm;
} struct_t;
long time_seconds(struct_t arrival)
Related Information
v Block on page 196
v Function Definitions on page 178
v Function Declarations on page 174
void
int
main (
void
parameters
) block_statement
%&
By default, main has the storage class extern and a return type of int. You can
also declare main to return void.
In C++, you cannot declare main as inline or static. You cannot call main from
within a program or take the address of main.
Arguments to main
|
|
|
You can declare the function main with or without parameters. Although you can
give any name to these parameters, common practice is to name them argc and
argv.
The first parameter, argc (argument count), has type int. It indicates how many
arguments you entered on the command line when running the program.
The second parameter, argv (argument vector), has type array of pointers to char
array objects. char array objects are null-terminated strings.
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. This array
Chapter 8. Functions
183
main()
contains the program name or the invocation name of the program you are running.
If the name cannot be determined, the first element in argv points to a null
character.
The compiler counts this name as one of the arguments to the function main. For
example, if you only enter the program name on the command line, argc has a
value of 1, and argv[0] points to the program name.
Regardless of the number of arguments that are entered on the command line,
argv[argc] always contains NULL.
Consider invoking this program from a command line with the following:
backward string1 string2
The arguments argc and argv would contain the following values:
Object
Value
argc
argv[0]
argv[1]
argv[2]
argv[3]
3
pointer to string backward
pointer to string string1
pointer to string string2
NULL
Related Information
v
v
v
v
v
184
The call to tester in the example may produce different results on different
compilers. Depending on the implementation, OS/390 C/C++ may evaluate x++ first,
Chapter 8. Functions
185
The following function call causes copies of a and b to be stored in a local area for
the function sum(). The function sum() runs 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(). The function
printf() receives a character string and the return value of sum(). The function
sum() receives the values of a and b:
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.
186
CBC3RAAX
/**
** This example shows how an argument is passed to a function
**/
#include <stdio.h>
void increment(int);
int main(void)
{
int count = 5;
/* value of count is passed to the function */
increment(count);
printf("count = %d\n", count);
}
return(0);
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 example, main passes the address of count to increment. This
example has changed the function increment to handle the pointer. It declares the
parameter x as a pointer. The contents to which x points are then incremented.
CBC3RAAY
/**
** This example shows how an address is passed to a function
**/
#include <stdio.h>
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);
}
return(0);
The output shows that the above example increases the variable count:
*x = 6
count = 6
Chapter 8. Functions
187
When you call the function printbig, it cannot modify the object of type bigvar
because a constant reference passes the object.
The following example shows how arguments are passed by reference. Note that
OS/390 C/C++ initializes the reference formal arguments with the actual arguments,
when you call the function.
CBC3X06A
/**
** This example shows how arguments are passed by reference
**/
#include <iostream.h>
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
188
CBC3X06B
/**
** This example illustrates default function arguments
**/
#include <iostream.h>
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;
}
In this example, the a referred to in the declaration of g() is the one at file scope. It
has the value 2 when g() is called. Consequently, this example prints 2 to standard
output. 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. Arguments with default values do not affect the type of a function.
The following example shows that a function with 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. You can call function f
without an explicit argument, but you cannot define the pointer badpointer without
specifying the type of the argument:
int f(int = 0);
void g()
{
int a = f(1);
int b = f();
}
int (*pointer)(int) = &f;
int (*badpointer)() = &f;
// ok
// ok, default argument used
// ok, type of f() specified (int)
// error, badpointer and f have
Chapter 8. Functions
189
f(int
f(int
f(int
f(int
//
//
//
//
valid
valid, add another default
valid, add another default
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
declaration, or a previous declaration of the function.
You cannot use local variables in default argument expressions. For example, the
C++ 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
}
OS/390 C/C++ checks the default arguments against the function declaration and
evaluates them when you call the function. The order of default argument
evaluation is undefined. Default argument expressions cannot use formal arguments
of a function, for example:
int f(int q = 3, int r = q); // error
190
Here, the compiler interprets the type D within the function declaration as the name
of an integer. The example hides the type D in 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, you cannot use the nonstatic member a as an initializer.
The member a does not exist until an object of class X is constructed. You can use
the static member b as an initializer, because OS/390 C++ creates b independently
of any objects of class X. You can declare the member b after you use it as a
default argument. The default values are not analyzed until after the final brace, },
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:
class C {
void f(int i = X<int,5>::y);
};
In the above example, the C++ compiler cannot process the default argument
X<int,5>::y until the end of the class. Consequently, it cannot tell that the <
represents the start of a template argument list and not the less than operator.
To avoid error messages, put parentheses around the expression that contains the
default argument:
class C {
void f( int i = (X<int,5>::y) );
};
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
example initializes the variable answer with the int value 30. The compiler checks
Chapter 8. Functions
191
//
//
//
//
Returns
Returns
Returns
Returns
no value
the value of result
the value 1
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 result returned is
undefined. In C++, the compiler issues an error message as well.
If main has a return type of int, and does not contain a return expression, it returns
the value zero.
Each time a function is called, new copies of its local variables are created. You can
reuse the storage for a local variable after the function has terminated.
Consequently, the function should not return a pointer to a local variable, or a
reference to a local variable.
If the function returns a class object, you may create a temporary object if the class
has copy constructors or a destructor. For more information, see Temporary
Objects on page 324.
Pointers to Functions
A pointer to a function points to the address of the functions executable code. You
can use pointers to call functions and to pass functions as arguments to other
functions. You cannot perform pointer arithmetic on pointers to functions. Use the
__cdecl keyword to declare a pointer to a function as a C linkage. For more
information, refer to __cdecl Keyword (C++ Only) on page 125.
Both the return type and argument types of the function determine the type of a
pointer to a function.
A declaration of a pointer to a function must have the pointer name in parentheses.
Without them, the compiler interprets the statement as a function that returns a
pointer to a specified return type. For example:
int *f(int a);
int (*g)(int a);
192
Pointers to Functions
In the first declaration, OS/390 C/C++ interprets f as a function that takes an int as
argument. It returns a pointer to an int. In the second declaration, OS/390 C/C++
interprets g as a pointer to a function that takes an int argument and that returns
an int.
Under OS/390 C/C++, if you pass a function pointer to a function, or the function
returns a function pointer, the declared or implied linkages must be the same. Use
the extern keyword with declarations in order to specify different linkages. Refer to
extern Storage Class Specifier on page 77 for more information.
The following example illustrates the correct and incorrect uses of function pointers
under OS/390 C/C++ :
#include <stdlib.h>
extern "C"
int cf();
extern "C++" int cxxf(); // C++ is included here for clarity;
// it is not required; if it is
// omitted, cxxf() will still have
// C++ linkage.
extern "C"
int (*c_fp)();
extern "C++" int (*cxx_fp)();
typedef int (*dft_fp_T)();
typedef int (dft_f_T)();
extern "C" {
typedef void (*cfp_T)();
typedef int (*cf_pT)();
void cfn();
void (*cfp)();
}
extern "C++" {
typedef int (*cxxf_pT)();
void cxxfn();
void (*cxxfp)();
}
extern "C" void f_cprm(int (*f)()) {
int (*s)() = cxxf;
// error, incompatible linkages-cxxf has
// C++ linkage, s has C linkage as it
// is included in the extern "C" wrapper
cxxf_pT j = cxxf;
// valid, both have C++ linkage
int (*i)() = cf;
// valid, both have C linkage
}
extern "C++" void f_cxprm(int (*f)()) {
int (*s)() = cf;
// error, incompatible linkages-cf has C
// linkage, s has C++ linkage as it is
// included in the extern "C++" wrapper
int (*i)() = cxxf;
// valid, both have C++ linkage
cf_pT
j = cf;
// valid, both have C linkage
}
main() {
c_fp
= cxxf;
//
//
cxx_fp = cf;
//
//
dft_fp_T dftfpT1 = cf;
//
//
dft_f_T *dftfT3 = cf;
//
//
dft_fp_T dftfpT5 = cxxf; //
193
Pointers to Functions
dft_f_T
*dftfT6 = cxxf;
//
valid
c_fp
= cf;
// valid
cxx_fp = cxxf;
// valid
f_cprm(cf);
// valid
f_cxprm(cxxf);
// valid
// The following errors are due to incompatible linkage of function
// arguments, type conversion not possible
f_cprm(cxxf);
// error - f_cprm expects a parameter with
// C linkage, but cxxf has C++ linkage
f_cxprm(cf);
// error - f_cxprm expects a parameter
// with C++ linkage, but cf has C linkage
For OS/390, linkage compatibility affects all C library functions that accept a
function pointer as a parameter. The qsort() function is an example of these
functions (see extern Storage Class Specifier on page 77 for a sample program).
Refer to the OS/390 C/C++ Run-Time Library Reference for more information.
For more information on pointers, see Pointers on page 95 and Pointer
Conversions on page 168.
Both member functions 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 evaluation order of the actual
arguments.
194
Chapter 9. Statements
This chapter describes the C and C++ language statements that are listed below:
v Labels
v Block on page 196
v break on page 197
v continue on page 199
v
v
v
v
v
v
v
do on page 201
Expression on page 202
for on page 203
goto on page 206
if on page 207
null on page 208
return on page 208
Labels
A label is an identifier that allows your program to transfer control to other
statements within the same function. It is the only type of identifier that has function
scope. Control is transferred to the statement following the label by means of the
goto or switch statements.
A labelled statement has the form:
%% identifier :
statement
%&
Examples
comment_complete : ;
/* null statement label */
test_for_null : if (NULL == pointer)
Related Information
v Scope in C on page 37
v Scope in C++ on page 47
v goto on page 206
v switch on page 210
Copyright IBM Corp. 1996, 2000
195
Block
Block
A block statement, or compound statement, lets you group any number of data
definitions, declarations, and statements into one statement. The compiler treats all
definitions, declarations, and statements that are enclosed within a single set of
braces as a single statement. You can use a block wherever a single statement is
allowed.
A block statement has the form:
%% {
'
'
type_definition
file_scope_data_declaration
block_scope_data_declaration
statement
%&
When control exits from a block, all objects with destructors that are defined in the
block are destroyed. Your program calls the destructor for an auto or a static local
object, only if it constructed the object. Your program must call the destructor
before, or as part of, the atexit function.
Your program also destroys local variables that are declared in a block on exit. It
destroys automatic variables defined in a loop at each iteration.
196
Block
Example
The following program shows how the values of data objects change in nested
blocks:
CBC3RAA1
1 /**
2 ** This example shows how data objects change in nested blocks.
3 **/
4
#include <stdio.h>
5
6
int main(void)
7
{
8
int x = 1;
/* Initialize x to 1 */
9
int y = 3;
10
11
if (y > 0)
12
{
13
int x = 2;
/* Initialize x to 2 */
14
printf("second x = %4d\n", x);
15
}
16
printf("first x = %4d\n", x);
17
18
return(0);
19
}
2
1
The function main defines two variables that are named x. The definition of x on line
8 retains storage while main is running. However, because the definition of x on line
13 occurs within a nested block, line 14 recognizes x as the variable defined on line
13. Because line 16 is not part of the nested block, the compiler recognizes x as the
variable defined on line 8.
Related Information
v Block Scope Data Declarations on page 72
v File Scope Data Declarations on page 73
v Storage Class Specifiers on page 74
v Type Specifiers on page 87
break
A break statement lets you end an iterative statement (do, for, while) or a switch
statement, and exit from it at any point other than the logical end.
A break statement has the form:
%% break ;
%&
In an iterative statement, 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 passes control out of the switch body to the next
statement outside the switch body.
Chapter 9. Statements
197
break
Restrictions
A break statement can only appear in the body of an iterative statement or a switch
statement.
Examples
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 following is an equivalent for statement, if string does not contain any
embedded null characters:
for (i = 0; (i < 5)&& (string[i] != '\0'); i++)
{
length++;
}
CBC3RAA2
/**
**
**
**
**
**/
#include <stdio.h>
#include <ctype.h>
#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++)
return(0);
198
*/
break
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 switch statement.
CBC3RAA
/**
** This example shows a switch statement with break statements.
**/
#include <stdio.h>
enum {morning, afternoon, evening} timeofday = morning;
int main(void) {
switch (timeofday) {
case (morning):
printf("Good Morning\n");
break;
case (evening):
printf("Good Evening\n");
break;
default:
printf("Good Day, eh\n");
Related Information
v do on page 201
v for on page 203
v switch on page 210
v while on page 214
continue
A continue statement lets you end the current iteration of a loop. Program control is
passed from the continue statement to the end of the loop body.
A continue statement has the form:
%% continue ;
%&
The continue statement ends the processing of the action part of an iterative (do,
for, or while) statement. It also moves control to the condition part of the
statement. If the iterative statement is a for statement, control moves to the third
expression in the condition part of the statement. It then moves 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.
Restrictions
A continue statement can only appear within the body of an iterative statement.
Chapter 9. Statements
199
continue
Examples
The following example shows a continue statement in a for statement. The
continue statement causes processing to skip over those elements of the array
rates that have values less than or equal to 1.
CBC3RAA3
/**
** This example shows a continue statement in a for statement.
**/
#include <stdio.h>
#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]);
}
}
*/
return(0);
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 ends.
Processing continues with the third expression of the inner loop. The inner loop
ends when it encounters the \0 escape sequence.
CBC3RAA4
/**
** 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 <stdio.h>
#include <ctype.h>
#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 (isnum(*pointer))
200
*/
continue
continue;
letter_count++;
}
printf("letter count = %d\n", letter_count);
}
return(0);
Compare this program with the program in 198, which shows the use of the break
statement to perform a similar function.
Related Information
v do
v for on page 203
v while on page 214
do
A do statement repeatedly runs a statement until the test expression evaluates to 0.
Because of the order of processing, OS/390 C/C++ runs the statement at least
once.
A do statement has the form:
%% do statement while ( expression )
%&
The body of the loop is run before the controlling while clause is evaluated. Further
processing of the do statement depends on the value of the while clause. If the
while clause does not evaluate to 0, the statement runs again. When the while
clause evaluates to 0, the statement ends. The controlling expression must be
evaluate to a scalar type.
A break, return, or goto statement can end the processing of a do statement, even
when the while clause does not evaluate to 0.
Example
The following statement prompts the user to enter a 1. If the user enters a 1, the
statement ends. If not, it displays another prompt. The example contains
error-checking code to verify that the user entered an integer value and to clear the
input stream if an error occurs.
CBC3X07E
/**
** This example illustrates the do statement.
**/
#include <iostream.h>
void main()
{
int reply1;
char c;
do
{
Chapter 9. Statements
201
do
cout << "Enter a 1: ";
cin >> reply1;
if (cin.fail())
{
cerr << "Not a valid number." << endl;
// Clear the error flag.
cin.clear(cin.rdstate() & ios::failbit);
cin.ignore(cin.rdbuf()->in_avail());
}
}
while (reply1 != 1);
Related Information
v break on page 197
v continue on page 199
v while on page 214
Expression
An expression statement contains an expression. The expression can be null.
Chapter 6. Expressions and Operators on page 133 describes expressions.
An expression statement has the form:
%%
expression
%&
An expression statement evaluates the given expression. Use it to assign the value
of the expression to a variable or to call a function.
Examples
printf("Account Number: \n");
marks = dollars * exch_rate;
(difference < 0) ? ++losses : ++gain;
switches = flags BIT_MASK;
/*
/*
/*
/*
*/
*/
*/
*/
v In every other case, if the compiler can parse the statement as a declaration, it
assumes the statement is 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);
202
Expression
In some cases, C++ syntax does not distinguish 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.) If the
compiler can interpret the statement both as a declaration and as an expression, it
interprets the statement as a declaration statement.
Note: The ambiguity is resolved only on a syntactic level. The resolution does not
use the meaning of the names, except to assess whether or not they are
type names.
The compiler resolves the following expressions into expression statements
because the ambiguous subexpression is followed by an assignment or an operator.
In these expressions, type_spec can be any type specifier:
type_spec(i)++;
type_spec(i,3)<<d;
type_spec(i)->l=24;
// expression statement
// expression statement
// expression statement
In the following examples, the ambiguity cannot be resolved syntactically, and the
compiler interprets the statements as declarations. type_spec is any type specifier:
type_spec(*i)(int);
type_spec(j)[5];
type_spec(m) = { 1, 2 };
type_spec(*k) (float(3));
//
//
//
//
declaration
declaration
declaration
declaration
The last statement above causes a compile-time error because you cannot initialize
a pointer with a float value.
Any ambiguous statement that is not resolved by the above rules is by default a
declaration statement. All of the following are declaration statements:
type_spec(a);
type_spec(*b)();
type_spec(c)=23;
type_spec(d),e,f,g=0;
type_spec(h)(e,3);
//
//
//
//
//
declaration
declaration
declaration
declaration
declaration
declaration of a function
declaration of a variable
expression-statement calling function a()
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.
for
A for statement lets you do the following:
v Evaluate an expression before the first iteration of the statement (initialization)
v Specify an expression to determine whether or not the statement should be
processed (controlling part)
Chapter 9. Statements
203
for
v Evaluate an expression after each iteration of the statement
v Repeatedly process the statement if the controlling part does not evaluate to
zero.
A for statement has the form:
%% for (
expression1
expression2
expression3
% statement
%&
expression1
expression2
expression3
A break, return, or goto statement can cause 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 end the for statement.
C++ Note: 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.
Examples
The following for statement prints the value of count 20 times. The for statement
initially sets the value of count to 1. After each iteration of the statement, it
increments count.
for (count = 1; count <= 20; count++)
printf("count = %d\n", count);
The following sequence of statements accomplishes the same task. Note the use of
the while statement instead of the for statement.
204
for
count = 1;
while (count <= 20)
{
printf("count = %d\n", count);
count++;
}
The following for statement will continue running 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. It declares and initializes two integers,
i, and j. The second comma, a comma operator, allows the program to increment
both i and j 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. It prints the values of an
array that has the dimensions [5][3]:
for (row = 0; row < 5; row++)
for (column = 0; column < 3; column++)
printf("%d\n", table[row][column]);
OS/390 C/C++ processes the outer statement 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. It executes the statement of the inner for
statement 3 times. The inner statement is executed as long as the value of column
is less than 3.
Related Information
v break on page 197
v continue on page 199
Chapter 9. Statements
205
goto
goto
A goto statement causes your program to unconditionally transfer control to the
statement that is associated with the label that is specified on the goto statement.
A goto statement has the form:
%% goto label_identifier ;
%&
Because the goto statement can interfere with the normal sequence of processing,
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. Thus, the
result is undefined. The label must appear in the same function as the goto.
If your program exits an active block by using a goto statement, OS/390 C/C++
destroys any local variables when it transfers control from that block.
Example
The following example shows a goto statement that is used to jump out of a nested
loop. You can write this function without using a goto statement.
CBC3RAA6
/**
** This example shows a goto statement that is used to
** jump out of a nested loop.
**/
#include <stdio.h>
void display(int matrix[3][3]);
int main(void)
{
int matrix[3][3]={1,2,3,4,5,2,8,9,10};
display(matrix);
return(0);
}
void display(int matrix[3][3])
{
int i, j;
206
if
if
An if statement lets you conditionally process a statement when the specified test
expression evaluates to a nonzero value. The expression must evaluate to a scalar
type. You can 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 runs. If the test expression evaluates to a nonzero value, the
statement following the expression runs and the else clause is ignored.
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
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. If the value of number is less than 0, it 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 that does not have an else
clause. Because an else clause always associates with the closest if statement,
you may have to use braces. The braces force a particular else clause to associate
with the correct if statement. In this example, omitting the braces causes the else
clause to associate with the nested if statement.
if (kegs > 0) {
if (furlongs > kegs)
fpk = furlongs/kegs;
}
else
fpk = 0;
The following example shows an if statement nested within an else clause. This
example tests multiple conditions. OS/390 C/C++ performs the tests in order of their
Chapter 9. Statements
207
if
appearance. If it evaluates one test to a nonzero value, OS/390 C/C++ runs the
statement, and ends the entire if statement.
if (value > 0)
++increase;
else if (value == 0)
++break_even;
else
++decrease;
null
The null statement performs no operation. It has the form:
%% ;
%&
A null statement can hold the label of a labeled statement or complete the syntax
of an iterative statement.
Example
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)
;
You can use a null statement when you require a label before the end of a block
statement, for example:
void func(void) {
if (error_detected)
goto depart;
/* further processing */
depart:; /* null statement required */
}
return
A return statement ends the processing of the current function and returns control to
the caller of the function.
A return statement has the form:
%% return
expression
%&
208
return
You cannot use a return statement with an expression when you declare the
function as returning type void.
C++ Note: In C++, if a function returns a class object with constructors, OS/390
C/C++ may construct a temporary class object. The temporary object is
not in the scope of the function that returns the temporary object, but is
local to the caller of the function.
When OS/390 C/C++ returns a function, it destroys all temporary local variables. If
local class objects with destructors exist, OS/390 C/C++ calls destructors. For more
details, see Temporary Objects on page 324.
Examples
return;
return result;
return 1;
return (x * x);
/*
/*
/*
/*
Returns
Returns
Returns
Returns
no value
the value of result
the value 1
the value of x * x
*/
*/
*/
*/
Chapter 9. Statements
209
return
Related Information
v Chapter 8. Functions on page 173
v Expression on page 202
switch
A switch statement lets you transfer control to different statements within the switch
body depending on the value of the switch expression. The switch expression must
evaluate to an integral value. The body of the switch statement contains case
clauses that consist of:
v A case label
v An optional default label
v A case expression
v A list of statements
If the value of the switch expression equals one of the case expression values,
OS/390 C/C++ processes the statements that follow that case expression. If not, it
processes any default label statements.
A switch statement has the form:
%% switch ( expression ) switch_body
%&
You enclose the switch body in braces. The switch body can contain definitions,
declarations, case clauses, and a default clause. Each case clause and default
clause can contain statements.
%% {
'
'
type_definition
file_scope_data_declaration
block_scope_data_declaration
'
default_clause
case_clause
case_clause
%&
210
%&
switch
A case label contains the word case, followed by an integral constant expression
and a colon. You can put multiple case labels anywhere that you can put one case
label. A case label has the form:
%&
%%
case_label
default :
case_label
' statement
%&
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. You can
refer to this expression as the switch expression.
OS/390 C/C++ compares the value of the switch expression with the value of the
expression in each case label. If it finds a matching value, it passes control to the
statement following the case label that contains the matching value. If there is no
matching value but there is a default label in the switch body, control passes to
the default labelled statement. If it does not find a matching value, and there is no
default label anywhere in the switch body, it does not process any part of the
switch body.
OS/390 C/C++ passes control to a statement in the switch body. It passes control
out of the switch body only when it encounters a break statement, or encounters
the last statement in the switch body.
If necessary, OS/390 C/C++ performs an integral promotion on the controlling
expression. It also converts all expressions in the case statements 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 cannot have
duplicate case labels in a switch statement.
You can put 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++ Note: You can have declarations in the body of the switch statement. In C++,
you cannot normally transfer control over a declaration containing an
initializer. However, you can transfer control if the declaration is located
Chapter 9. Statements
211
switch
in an inner block that is completely bypassed by the transfer of control.
You must contain all declarations within the body of a switch statement
that contains initializers in an inner block.
Examples
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, OS/390 C/C++ processes the
statements following the case expression. It processes these statements until it
encounters a break statement, or reaches the end of the switch body. In the
following example, break statements are not present. If the value of text[i] is
equal to 'A', the compiler increments all three counters. 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<sizeof(text); i++) {
switch (text[i])
{
case 'A':
capa++;
case 'a':
lettera++;
212
switch
}
default:
total++;
The following switch statement performs the same statements for more than one
case label:
CBC3RABI
/**
** This example contains a switch statement that performs
** the same statement for more than one case label.
**/
#include <stdio.h>
int main(void)
{
int month;
/* Read in a month value */
printf("Enter month: ");
scanf("%d", &month);
/* Tell what season it falls into */
switch (month)
{
case 12:
case 1:
case 2:
printf("month %d is a winter month\n", month);
break;
case 3:
case 4:
case 5:
printf("month %d is a spring month\n", month);
break;
case 6:
case 7:
case 8:
printf("month %d is a summer month\n", month);
break;
}
}
case 9:
case 10:
case 11:
printf("month %d is a fall month\n", month);
break;
case 66:
case 99:
default:
printf("month %d is not a valid month\n", month);
return(0);
If the expression month has the value 3, OS/390 C/C++ passes control to the
following statement:
printf("month %d is a spring month\n", month);
The break statement passes control to the statement following the switch body.
Chapter 9. Statements
213
switch
Related Information
v break on page 197.
while
A while statement repeatedly runs the body of a loop until the controlling expression
evaluates to 0.
A while statement has the form:
%% while ( expression )
statement
%&
OS/390 C/C++ evaluates the expression to determine whether or not to process the
body of the loop. The expression must be convertible to a scalar type. If the
expression evaluates to 0, the body of the loop never runs. If the expression does
not evaluate to 0, OS/390 C/C++ processes the loop body. After the body has run,
control passes back to the expression. Further processing depends on the value of
the condition.
A break, return, or goto statement can cause a while statement to end, even when
the condition does not evaluate to 0.
Example
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.
CBC3RAA7
/**
** This example illustrates the while statement.
**/
#define MAX_INDEX (sizeof(item) / sizeof(item[0]))
#include <stdio.h>
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;
}
}
return(0);
Related Information
v break on page 197
v goto on page 206
v return on page 208
214
Preprocessor Overview
Preprocessing is a step that takes place before compilation that lets you:
v Replace tokens in the current file with specified replacement tokens.
v Imbed files within the current file.
v Conditionally compile sections of the current file.
v Generate diagnostic messages.
v Change the source line number of the next line, and change the file name of the
current file.
A token is a series of characters that are delimited by white space. The only white
space that is allowed on a preprocessor directive is a blank (space), the horizontal
tab, and comments. The new-line character can also separate preprocessor tokens.
The preprocessed source program file must be a valid C or C++ program.
The following directives control the preprocessor:
#define
#undef
#error
#include
#if
#ifdef
#ifndef
#else
215
Preprocessor Overview
#elif
#endif
#line
#pragma
Phases of Preprocessing
Preprocessing appears as if it occurs in several phases.
1. It introduces new-line characters as needed to replace system-dependent
end-of-line indicators, and performs any other system-dependent character-set
translations. It replaces trigraph sequences with equivalent single characters.
2. It deletes each \ (backslash) that is followed by a new-line character pair. It
appends the next source line to the line that contained the sequence.
3. It decomposes the source text into preprocessing tokens and sequences of
white space. A single white space replaces each comment. A source file cannot
end with a partial token or comment.
4. It executes preprocessing directives, and expands macros.
5. It replaces escape sequences in character constants and string literals by their
equivalent values.
6. It concatenates adjacent string literals.
The rest of the compilation process operates on the preprocessor output, which is
syntactically and semantically analyzed and translated. The compiler output is then
linked as necessary with other programs and libraries.
216
#define
define identifier
(
% '
,
'
identifier
%&
identifier
character
Object-Like Macros
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
If the above statement appears after this definition and in the same file as the
definition, the preprocessor changes the statement to the following statement, in the
output of the preprocessor:
int arry[1000];
217
#define
Identifiers that are partially built from a macro expansion may not be produced.
Therefore, the following example does not produce the identifier abcdefg, and
results in a syntax error:
#define d efg
abcd
Function-Like Macros
Function-like macro definition:
An identifier followed by a parameter list in parentheses and the
replacement tokens. OS/390 C/C++ imbeds the parameters in the
replacement code. 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 list of arguments in parentheses. A comma must
separate each argument. Once the preprocessor identifies a function-like
macro invocation, it substitutes an argument. It replaces a parameter in the
replacement code by the corresponding argument. The preprocessor
completely replaces any macro invocations that are contained in the
argument itself, 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);
((c) * (c))
Without parentheses in the definition, the preprocessor does not preserve the
correct order of evaluation, and its output is:
y = (a + b * a + b);
218
#define
The preprocessor converts the arguments of the single number sign operator (#)
and the double number sign operator ## before it replaces parameters in a
function-like macro.
The number of arguments in a macro invocation must be the same as the number
of parameters in the corresponding macro definition.
Commas in the macro invocation argument list do not act as argument separators
when they are:
v In character constants
v In string literals
v Surrounded by parentheses.
Once defined, a preprocessor identifier remains defined and in scope independent
of the scoping rules of the language. The scope of a macro definition begins at the
definition and it does not end until it encounters a corresponding #undef directive. If
there is no corresponding #undef directive, the scope of the macro definition lasts
until the end of the compilation unit.
The preprocessor does not fully expand a recursive macro. For example, consider
the following definition:
#define x(a,b) x(a+1,b+1) + 4
The above macro definition expands to the following, rather than trying to expand
the macro x over and over, within itself:
x(20+1,10+1) + 4
After the preprocessor expands the macro x, the macro is a call to function x().
You do not require a definition to specify replacement tokens. The following
definition removes all instances of the token debug from subsequent lines in the
current file:
#define debug
You can change the definition of a defined identifier or macro with a second
preprocessor #define directive. However, the second preprocessor #define
directive must be preceded by a preprocessor #undef directive. This is described in
Scope of Macro Names (#undef) on page 221. The #undef directive nullifies the
first definition, so that you can use the same identifier in a redefinition.
Within the text of the program, the preprocessor does not scan character constants
or string constants for macro invocations.
219
#define
return(0);
return(0);
220
#undef
undef identifier
%&
If you have not currently defined the identifier as a macro, the preprocessor ignores
#undef.
The preprocessor does not replace any occurrences of the identifiers BUFFER and
SQR that follow these #undef directives 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.
#x
The preprocessor expands all subsequent invocations of the macro ABC into a
character string literal that contains the argument that is passed to ABC. For
example:
Invocation
ABC(1)
ABC(Hello there)
"1"
"Hello there"
Note that you can represent the single number sign character # by the trigraph ??=.
Do not confuse the # operator with the null directive documented in Null Directive
(#) on page 238.
Use the # operator in a function-like macro definition according to the following
rules:
v The preprocessor converts a parameter that follows the # operator in a
function-like macro into a character string literal that contains the argument that
is passed to the macro.
Chapter 10. Preprocessor Directives
221
# Operator
v The preprocessor deletes white-space characters that appear before or after the
argument that is passed to the macro.
v The preprocessor uses a single space character to replace multiple white-space
characters that are imbedded within the argument that is passed to the macro.
v If the argument that is passed to the macro contains a string literal, and if a \
(backslash) character appears within the literal, the preprocessor inserts a
second \ character before the original one when it expands the macro.
v If the argument passed to the macro contains a " (double quotation mark)
character, a \ character is inserted before the " when the macro is expanded.
v If the argument passed to the macro contains a ' (single quotation mark)
character, a \ character is inserted before the ' when the macro is expanded.
v The conversion of an argument into a string literal occurs before macro
expansion on that argument.
v 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.
v If the result of the macro expansion is not a valid character string literal, the
behavior is undefined.
See Function-Like Macros on page 218 for more information about function-like
macros.
#x
STR(x)
1
Invocation
Related Information
v Macro Definition and Expansion (#define) on page 217
v Scope of Macro Names (#undef) on page 221
x##y
The preprocessor concatenates the last token of the argument for x with the first
token of the argument for y.
For example,
222
Invocation
XY(1, 2)
XY(Green, house)
12
Greenhouse
## Operator
Note that you can represent the # character by the trigraph ??=.
ArgArg(x, y)
ArgText(x)
TextArg(x)
TextText
Jitter
bug
Jitterbug
x##y
x##TEXT
TEXT##x
TEXT##text
1
2
3
Invocation
ArgArg(lady, bug)
ArgText(con)
TextArg(book)
TextText
ArgArg(Jitter, bug)
ladybug
conTEXT
TEXTbook
TEXTtext
3
Related Information
%% #
%&
Use the #error directive as a safety check during compilation. For example, if your
program uses preprocessor conditional compilation directives, put #error directives
in the source file. The directives prevent code generation if a section of the program
is reached that should be bypassed.
223
#error
For example, consider the following directive:
#error Error in TESTPGM1 - This section should not be compiled
Related Information
v Conditional Compilation Directives on page 233
include
"
<
//
//
file_name "
%&
file_name >
You can specify an OS/390 data set or an HFS file for filename. Use double
slashes (//) before the filename to indicate that the file is an OS/390 data set. Use
a single slash (/) anywhere in the filename to indicate an HFS file. See the OS/390
C/C++ Users Guide for more information on specifying include file names.
The preprocessor resolves macros that are contained in an #include directive. After
macro replacement, the resulting token sequence must consist of a file name that is
enclosed in either double quotation marks, or the characters < and >.
For example:
#define MONTH <july.h>
#include MONTH
If you enclose the file name in double quotation marks ("), the preprocessor
searches the directories or libraries that contain the user source files. It then
searches a standard or specified sequence of places, until it finds the specified file.
For example:
#include "payroll.h"
If you enclose the file name in the characters < and >, the preprocessor searches
only the standard or specified places for the specified file. For example:
#include <stdio.h>
The new-line and > characters cannot appear in a file name that is delimited by <
and >. The new-line and " (double quotation marks) characters cannot appear in a
file name that is delimited by double quotation marks. However, the > character can
appear in such a file name.
For more information about include file search paths and compiler options, see the
OS/390 C/C++ Users Guide.
224
#include
Declarations that are used by several files can be placed in one file and included
with #include in each file that uses them. 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"
<stdio.h>
Description
__DATE__
A character string literal that contains the date when the source file
was compiled.
The value of __DATE__ changes as the compiler processes any
include files that are part of your source program. The date is in the
form:
"Mmm dd yyyy"
where:
Mmm
dd
Represents the day. If the day is less than 10, the first d is
a blank character.
yyyy
225
A character string literal that contains the name of the source file.
The value of __FILE__ changes as the compiler processes include
files that are part of your source program. You can set it with the
#line directive, described in Line Control (#line) on page 237.
__LINE__
__STDC__
__TIME__
A character string literal that contains the time when the source file
was compiled.
The value of __TIME__ changes as the compiler processes any
include files that are part of your source program. The time is in the
form:
"hh:mm:ss"
where:
hh
mm
ss
Note: The MVS command SET DATE does not affect the value
returned by this macro, or the value returned by the time()
function.
__cplusplus
For C++ programs, the preprocessor sets this macro to the integer
1, which indicates that the compiler is a C++ compiler. Note that
this macro name has no trailing underscores.
226
Macro Name
Description
__ANSI__
|
|
|
|
__CHARSET_LIB__
The preprocessor defines the macro __CHARSET_LIB to a value of 0
when you specify the EBCDIC compiler option, and to a value of 1
when you specify the ASCII compiler option.
__CODESET__
A string literal that represents the character code set of the LOCALE
compile option. If you do not use the LOCALE compile option, the
macro is undefined.
__COMMONC__
__COMPAT__
__COMPILER_VER__
The compiler version. The format of the version number that is
provided by the macro is hex PVRRMMMM:
v P represents the compiler product
0 for C/370
1 for AD/Cycle C/370 and C/C++ for MVS/ESA
2 for OS/390 C/C++
v V represents the version number
v RR represents the release number
v MMMM represents the modification number
In OS/390 C/C++ Version 2 Release 10, the value of the macro is
X'220A0000'.
|
|
__DIGRAPHS__
__DLL__
This macro allows you to write conditional code that depends upon
whether or not you have compiled your program as DLL code. For
C++, the preprocessor always defines the macro as 1. For C, the
preprocessor defines the macro as 1 if you specify the DLL compiler
option. Otherwise, it is undefined.
__EXTENDED__
__FILETAG__
A string literal that represents the character code set of the filetag
pragma associated with the current file. If no filetag pragma is
present, the macro is undefined.
Chapter 10. Preprocessor Directives
227
A character string that contains the name of the function that the
OS/390 C/C++ is currently compiling.
__HHW_370__
__HOS_MVS__
__IBMC__
|
|
__IBMCPP__
C++ Only. This macro indicates the version number of the OS/390
C++ compiler. The format of the version number that is provided by
the macro is integer PVRRM:
v P represents the compiler product
0 for C/370
1 for AD/Cycle C/370 and C/C++ for MVS/ESA
2 for OS/390 C/C++
v V represents the version number
v RR represents the release number
v M represents the modification number
In OS/390 C/C++ Version 2 Release 10, the value of the macro is
22100.
|
|
__IGNERRNO__
__INITAUTO__
228
__LIBREL__
__LOCALE__
This macro contains a string literal that represents the locale of the
LOCALE compile option. If you do not supply a LOCALE compile
option, the macro is undefined.
The following example illustrates how to set the runtime locale to
the compile-time locale:
main()
{
setlocale(LC_ALL, __LOCALE__);
.
.
.
_LONG_LONG
__LONGNAME__
For C, the integer 1 indicates that you have specified the LONGNAME
compile option or pragma. Otherwise the macro is undefined. For
C++, the value of __LONGNAME__ is always 1, even if you specify
NOLONGNAME.
|
|
C++ Note: In C++, long names are always in the compilation unit.
The LONGNAME compile option in C++ controls whether
non-C++ names will be truncated and uppercased, or
left alone. You can use this option to interface with
existing C code that was compiled with NOLONGNAME, so
that the names match.
|
|
|
|
|
|
_MI_BUILTIN
This macro is defined to be 0 for language level ANSI, and 1 for all
other language levels. When it is defined as 1, machine instruction
built-in functions can be called. If the machine instruction built-in
functions are required under language level ANSI, the user needs
to define the _MI_BUILTIN macro by specifying the DEFINE compile
time option.
229
__SAA__
__SAA_L2__
__STRING_CODE_SET__
This macro allows you to change the code page that the compiler
uses for character string literals (character data enclosed in double
quotation marks). To use this macro, you must specify it with the
DEFINE compiler option. The following example shows you how to
do this:
DEFINE(__STRING_CODE_SET__="ISO8859-1")
This macro affects all source files that are processed within a
compilation unit, including user header files, and system header
files. All string literals within a compilation unit must use the same
code page. Note that you can also use the CONVLIT compiler option
instead of this macro. For more information on this option, see the
OS/390 C/C++ Users Guide.
The macro does not affect the following types of string literals:
v String literals that are used in #include directives
v String literals that are used in #pragma directives
v String literals that are used to specify linkage, such as extern
"C" (C++ only)
The following restrictions apply to this macro:
v You cannot specify this macro if you have also used predefined
macros (such as __TIMESTAMP__) that return string literals.
__TARGET_LIB__
The target library version. The format of the version number
provided is hex PVRRMMMM:
v P represents the C or C/C++ library product
0 for C/370
1 for Language Environment/370 and Language Environment
for MVS & VM
2 for OS/390 Release 2 and later
v V represents the version number
v RR represents the release number
v MMMM represents the modification number.
The value of the __TARGET_LIB__ macro depends on the setting of
the TARGET compiler option. Refer to the OS/390 C/C++ Users
Guide for more information on the TARGET option. OS/390 C/C++
sets __TARGET_LIB__ as follows:
TARGET Suboption
__TARGET_LIB__ Setting
230
OSV2R10
0x220A0000
OSV2R9
0x22090000
OSV2R8
0x22080000
OSV2R7
0x22070000
OSV2R6
0x22060000
OSV2R5
0x22050000
OSV2R4
0x22040000
OSV1R3
0x21030000
OSV1R2
0x21020000
0xnnnnnnnn
0xnnnnnnnnn
__TEMPINC__
C++ Only. This macro indicates that the compiler is using the
template-implementation file method of resolving template functions.
It is defined as 1 if you are using the TEMPINC compile option.
__THW_370__
__TIMESTAMP__ A character string literal that contains the date and time when the
source file was last modified.
The value of __TIMESTAMP__ changes as the compiler processes
any include files that are part of your source program. The date and
time are 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
dd
Represents the day. If the day is less than 10, the first d is
a blank character.
hh
mm
ss
yyyy
231
|
|
|
__370__
__XPLINK__
CBC3X08B
/**
** This example illustrates the __FUNCTION__ predefined macro
** in a C++ program.
**/
#include <stdio.h>
int foo(int);
main(int argc, char **argv) {
int k = 1;
printf (" In function %s \n",__FUNCTION__);
foo(k);
}
int foo (int i) {
printf (" In function %s \n",__FUNCTION__);
}
CBC3X08C
/**
** This example illustrates the __FUNCTION__ predefined macro
** in a C++ program with virtual functions.
**/
232
Related Information
if TEST <=10
else
#
endif
#else
#endif
/*
*/
10 */
*/
233
#if, #elif
The #if and #elif directives compare the value of the expression to zero.
If the constant expression evaluates to a nonzero value, the preprocessor passes
the tokens that immediately follow the condition to the compiler.
Consider when the expression evaluates to zero and the conditional compilation
directive contains a preprocessor #elif directive. In that case, the preprocessor
passes the source text located between the #elif and the next #elif or
preprocessor #else directive on to the compiler. The #elif directive cannot appear
after the preprocessor #else directive.
All macros are expanded, any defined expressions are processed and all remaining
identifiers are replaced with the token 0.
%% #
if
elif
%&
The expressions that are tested must be integer constant expressions with the
following properties:
v They must perform arithmetic using long int values.
v The expression can contain defined macros. No other identifiers can appear in
the expression.
v 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 you have defined the identifier in the preprocessor; otherwise they
evaluate to 0 (zero):
defined identifier
defined(identifier)
For example:
#if defined(TEST1) || defined(TEST2)
234
#ifdef
The #ifdef directive checks for the existence of macro definitions.
If you have defined the identifier that is specified as a macro, the preprocessor
passes the tokens that immediately follow the condition on to the compiler.
The preprocessor #ifdef directive has the form:
%% #
token_sequence
%&
#ifndef
The #ifndef directive checks for the existence of macro definitions.
If you have not defined the identifier that is specified as a macro, the preprocessor
passes on the tokens that immediately follow the condition to the compiler.
The preprocessor #ifndef directive has the form:
%% #
token_sequence
%&
An identifier must follow the #ifndef keyword. The following example defines
MAX_LEN to be 50 if EXTENDED is not defined for the preprocessor. Otherwise, the
example defines MAX_LEN to be 75.
#ifndef EXTENDED
#
define MAX_LEN 50
#else
#
define MAX_LEN 75
#endif
235
#else
Consider when the condition specified in the #if, #ifdef, or #ifndef directive
evaluates to 0, and the conditional compilation directive contains a #else directive.
In that case, the preprocessor passes the source text located between the #else
directive and the #endif directive to the compiler.
The preprocessor #else directive has the form:
%% #
else '
token_sequence
%&
#endif
The preprocessor #endif directive ends the conditional compilation directive.
It has the form:
%% #
endif
CBC3RABC
/**
** This example contains preprocessor
** conditional compilation directives.
**/
#include <stdio.h>
int main(void)
{
static int array[ ] = { 1, 2, 3, 4, 5 };
int i;
for (i = 0; i <= 4; i++)
{
array[i] *= 2;
236
%&
}
return(0);
line
decimal_constant
characters
"
%&
file_name "
237
#line
CBC3RABD
/**
** This example illustrates #line directives.
**/
#include <stdio.h>
#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_ _);
}
%% #
238
pragma '
character_sequence
%&
#pragma
In the above syntax diagram, character_sequence is a series of characters that
gives a specific compiler instruction and arguments, if any.
The character_sequence on a pragma is not subject to macro substitutions, unless
otherwise stated.
You can specify more than one pragma construct on a single #pragma directive. The
compiler ignores unrecognized pragmas.
The OS/390 C/C++ compiler recognizes the following pragmas:
chars
checkout
comment
convlit
csect
define
disjoint
environment
export
filetag
hdrstop
implementation
info
inline
239
#pragma
240
isolated_call
langlvl
leaves
linkage
longname
map
margins
noinline
options
option_override
pack
page
pagesize
priority
reachable
runopts
#pragma
sequence
skip
strings
subtitle
target
title
variable
wsizeof
Restriction on Number of
Occurrences
Restriction on Placement
C++
chars
Once.
yes
yes
yes
yes
yes
yes
yes
yes
yes
yes
checkout
comment
csect
convlit
define
disjoint
environment
Cannot export the main() function.
Once per file scope.
yes
yes
yes
yes
yes
hdrstop
implementation
yes
yes
export
filetag
yes
yes
241
#pragma
Table 12. Restrictions on #pragmas (continued)
#pragma
Restriction on Number of
Occurrences
Restriction on Placement
info
C++
yes
inline
At file scope.
yes
isolated_call
yes
yes
noinline
At file scope.
yes
yes
yes
yes
leaves
linkage
longname
Once.
yes
yes
yes
map
yes
yes
margins
yes
yes
options
yes
option_override
yes
yes
pack
yes
yes
page
yes
pagesize
yes
priority
yes
reachable
yes
yes
runopts
yes
yes
sequence
yes
yes
skip
yes
strings
Once.
subtitle
target
yes
yes
yes
Once.
title
yes
variable
yes
yes
wsizeof
yes
yes
IPA Considerations
Interprocedural Analysis (IPA), through the IPA compiler option, is a mechanism for
performing optimizations across the compilation units of your OS/390 C or C++
program. IPA also performs optimizations not otherwise available with the C/C++
compiler. Refer to the OS/390 C/C++ Programming Guide for an overview of IPA.
Many #pragma directives do not have any special behavior under IPA. They have
the same effect on a program compiled with or without the IPA option.
242
#pragma
You may see changes during the IPA Link step, due to the effect of a #pragma
directive. The IPA Link step detects and resolves the conflicting effects of #pragma
directives, and the conflicting effects of #pragma directives and compiler options that
you specified for different compilation units. There may also be conflicting effects
between #pragma directives and equivalent compiler options that you specified for
the IPA Link step.
IPA resolves these conflicts similar to the way it resolves conflicting effects of
compiler options that are specified for the IPA Compile step and the IPA Link step.
The Compiler Options Map section of the IPA Link step listing shows the conflicting
effects between compiler options and #pragma directives, along with the resolutions.
For those #pragma directives where there are special considerations for IPA, the
following #pragma descriptions include IPA-related information.
chars
The #pragma chars directive specifies that the compiler is to treat all char objects as
signed or unsigned.
%% #
pragma chars (
unsigned
signed
%&
This pragma must appear on the first #pragma directive. It must also appear before
any code or directive, except for the pragmas filetag, longname, langlvl or target.
These pragmas may precede this directive. Once specified, it applies to the rest of
the file and you cannot turn it off. If a source file contains any functions that you
want to compile without #pragma chars, place these functions in a different file.
The default character type behaves like an unsigned char.
checkout
The #pragma checkout directive is a OS/390 C/C++ directive and an addition to the
SAA Standard.
This pragma can appear anywhere that a preprocessor directive is valid.
%% #
pragma checkout (
resume
suspend
%&
With #pragma checkout, you can suspend the diagnostics that the CHECKOUT C
compiler option or the INFO C++ compiler option performs during specific portions of
your program. You can then resume the same level of diagnostics later in the file.
Nested #pragma checkout directives are allowed and behave as the following
example demonstrates:
243
#pragma
/* Assume CHECKOUT(PPTRACE) had been specified */
#pragma checkout(suspend) /* No CHECKOUT diagnostics are performed */
...
#pragma checkout(suspend) /* No effect */
...
#pragma checkout(resume)
/* No effect */
...
#pragma checkout(resume)
/* CHECKOUT(PPTRACE) diagnostics continue */
comment
The #pragma comment directive places a comment into the object module. This
pragma must appear before any C or C++ code or directive in a source file. The
"token_sequence" field in this pragma has a 1024-byte limit.
%% #
pragma comment
% (
compiler
date
timestamp
copyright
user
%
)
%&
date
timestamp
The compiler appends the date and time of the last modification of
the source in an END information record at the end of the
generated object module. OS/390 C/C++ does not include the date
and time when it generates an executable nor does it load the date
and time into memory when it runs the program. This information
can be printed out using the C370LIB utility with the MAP option.
If OS/390 C/C++ cannot find the timestamp for a source file, the
#pragma comment directive returns Mon Jan 1 0:00:01 1990.
244
copyright
user
#pragma
included in the load module. Note that OS/390 C/C++ does not
necessarily load it into memory when it runs the program. OS/390
C/C++ places the token_sequence on END records in columns 34
to 71.
The characters in the token_sequence field, if specified, must be enclosed in double
quotation marks (").
You can display the object-file comments by using the MAP option for the C370LIB
utility.
IPA Considerations
The #pragma comment directive affects the IPA Compile step only if the OBJECT
suboption of the IPA compile option is in effect.
During the partitioning process in the IPA Link step, the compiler places the text
string information #pragma comment at the beginning of partition 0. Partition 0 is the
initialization partition.
convlit
The #pragma convlit directive allows you to suspend the string literal conversion
that the convlit compiler option performs during specific portions of your program.
You can then resume the conversion at some later point in the file.
%% #
pragma convlit (
resume
suspend
%&
The pragma is effective only when you specify the CONVLIT compile option.
If you select the PPONLY option, OS/390 C/C++ echoes the convlit pragma to the
expanded source file.
You can nest #pragma convlit directives. They behave as the following example
demonstrates:
/* Assume CONVLIT (<codepage>) had been specified */
#pragma convlit(suspend) /* No string literal conversion */
...
#pragma convlit(suspend) /* No effect */
...
#pragma convlit(resume)
/* No effect */
...
#pragma convlit(resume)
/* String literal conversion continues
*/
245
#pragma
#pragma convlit(resume)
}
puts(str);
csect
The #pragma csect directive identifies the name for either the code, static, or debug
control section (CSECT).
%% #
pragma csect (
CODE
STATIC
TEST
%&
Specifies the CSECT that contains the executable code (C functions) and
constant data.
static Designates the CSECT that contains all program variables with the static
storage class and all character strings.
test
Designates the CSECT that contains debug information. You must specify
the TEST option.
The above syntax encloses the name in double quotation marks. This is the name
that is used for the applicable CSECT (code, static, or test). OS/390 C/C++ does
not map the name in any way, including uppercasing. If the name is greater than 8
characters, you must turn on the LONGNAME option and use the binder. The name
must not conflict with the name of an exposed name (external function or object) in
a source file. In addition, it must not conflict with another #pragma csect directive or
#pragma map directive. For example, the name of the code CSECT must differ from
the name of the static and test CSECTs.
At most, three #pragma csect directives can appear in a source program as follows:
v One for the code CSECT
v One for the static CSECT
v One for the debug CSECT
Consider when there is no #pragma csect directive in the source file and you
specify the CSECT compile option. In this case, OS/390 C/C++ automatically
generates CSECT names from the source file name. For examples that show the
file names that are generated when using either the #pragma csect or the CSECT
compile option, see the section that describes the CSECT option in the OS/390
C/C++ Users Guide.
Private code has a disadvantage. When new code is linked to an executable
containing old code, the new code replaces the old. The old code, however, is not
discarded from the executable. The size of the executable will grow, and you may
get duplicates of functions. Naming the CSECTs with this directive replaces the old
code with the new, and removes the old code from the executable. If you want
replacement and removal, name the code, static, and test CSECT.
246
#pragma
IPA Considerations
Use the #pragma csect directive when naming regular objects only if the OBJECT
suboption of the IPA compile option is in effect. Otherwise, the compiler discards
the CSECT names that #pragma csect generated.
Refer to the IPA Link Step chapter in the OS/390 C/C++ Users Guide for
information on how the IPA Link step sets CSECT names.
pragma define (
template_class_name )
%&
The pragma can appear anywhere that a declaration is allowed. Use the pragma to
organize your program to efficiently or automatically generate template functions.
disjoint (C Only)
The #pragma disjoint directive lists the identifiers that are not aliased to each other
within the scope of their use. In the following syntax diagram, identifier is the name
of a variable:
%% #pragma disjoint
identifier '
% (
'
identifier
'
%&
The directive informs the compiler that none of the identifiers listed shares the same
physical storage, which provides more opportunity for optimizations. If any
identifiers actually share physical storage, the pragma may give incorrect results.
The pragma can appear anywhere in the source program that a declaration is
allowed. An identifier in the directive must be visible at the point in the program
where the pragma appears. The identifiers in the disjoint name list cannot refer to
any of the following:
v A member of a class, structure, or union
v A structure, union, or enumeration tag
v An enumeration constant
v A typedef name
v A label
You must declare the identifiers before using them in the pragma. Your program
must not dereference a pointer in the identifier list nor use it as a function argument
before it appears in the directive.
247
#pragma
The following example shows the use of #pragma disjoint.
int a, b, *ptr_a, *ptr_b;
#pragma disjoint(*ptr_a, b)
/* *ptr_a never points to b */
#pragma disjoint(*ptr_b, a)
/* *ptr_b never points to a */
one_function()
{
b = 6;
*ptr_a = 7;
/* Assignment will not change the value of b
}
another_function(b);
*/
*/
External pointer ptr_a does not share storage with and never points to the external
variable b. Consequently, assigning 7 to the object to which ptr_a points will not
change the value of b. Likewise, external pointer ptr_b does not share storage with
and never points to the external variable a. The compiler can assume that the
argument to another_function has the value 6 and will not reload the variable from
memory.
environment (C Only)
The #pragma environment directive is an OS/390 C directive, and an addition to the
SAA Standard.
%% #
pragma environment (
function
,nolib
%&
With the #pragma environment directive, you can use OS/390 C code as an
assembler substitute. See the OS/390 C/C++ Programming Guide for more
information on this use. The directive allows you to do the following:
v Specify entry points other than main
v Omit setting up an OS/390 C environment on entry to this function
v Specify several system exits that are written in OS/390 C code in the same
executable
If you specify nolib, the environment is established, and the library is not loaded at
run time. If you do not specify anything, the library is loaded.
Note: If you specify any other value than nolib after the function name, behavior is
not defined.
export
The #pragma export directive declares that a function or variable is to be exported.
It also specifies the name of the function or variable to be referenced outside the
module. You can use this #pragma to export functions or variables from a DLL
module.
%% #
pragma export (
function
variable
#pragma export is an OS/390 C/C++ specific directive and an addition to the SAA
standard.
248
%&
#pragma
With the #pragma export directive, you can export specific functions and variables to
the users of your DLL. See the OS/390 C/C++ Programming Guide for more
information on creating and using DLLs.
You can specify this pragma anywhere in the DLL source code, on its own line, or
with other pragmas. You can also specify it before or after the definition of the
variable or function. You must externally define the exported function or variable.
If the specification for a const variable in a #pragma export directive conflicts with
the ROCONST option, the pragma directive takes precedence over the compiler option,
and the compiler issues an informational message. The const variable gets
exported and it is considered re-entrant.
Note: You cannot export the main() function. You can also use the _Export
keyword to export a function.
IPA Considerations
If you specify this #pragma in your source code in the IPA Compile step, you cannot
override the effects of this #pragma on the IPA Link step.
filetag
The #pragma filetag directive specifies the code set in which the source code was
entered.
%% #
%&
Since the # character is variant between code sets, use the trigraph representation
??= instead of # as illustrated below.
The #pragma filetag directive must appear at most once per source file. It must
appear before the first statement or directive, except for all conditional compilation
directives, which may precede this directive. For example:
??=ifdef COMPILER_VER
/* This is allowed. */
??=pragma filetag ("code set")
??=endif
It should not appear in combination with any other #pragma directives. For example,
the directive is incorrect:
??=pragma filetag ("IBM-1047") export (baffle_1)
If there are comments before the pragma, OS/390 C/C++ does not translate them
to the code page that is associated with the LOCALE option.
See the OS/390 C/C++ Programming Guide for details on using this directive with
the LOCALE option.
hdrstop
The #pragma hdrstop directive manually terminates the initial sequence of #include
directives that are being considered for precompilation.
249
#pragma
%% #
It
v
v
v
pragma hdrstop
%&
The OS/390 C/C++ Users Guide describes how to structure your files so the
compiler can take full advantage of the precompiled headers.
Examples
The following example only precompiles the header h1.h by using the file
default.pch (provided you specify USEPCH or GENPCH). If you specify
USEPCH(dave.pch) GENPCH(john.pch), the compiler will look for the precompiled
headers in john.pch and will regenerate them if they are not found or not usable.
#include "h1.h"
#pragma hdrstop
#include "h2.h"
main () {}
The following example does not use nor does it generate precompiled headers for
the compilation, even if you specify GENPCH or USEPCH.
#pragma hdrstop
#include "h1.h"
#include "h2.h"
main () {}
pragma implementation (
string_literal )
%&
This pragma can appear anywhere that a declaration is allowed. Use this pragma to
organize your program to efficiently or automatically generate template functions.
Note: #pragma implementation is only effective if the TEMPINC option is in effect. If
the NOTEMPINC option is in effect, you must test the value of the __TEMPINC__
macro, and conditionally include the required source.
pragma info (
suspend
resume
You can use this pragma directive in place of the INFO option.
250
%&
#pragma
Use #pragma info suspend to suspend the diagnostics that the INFO compiler option
performs during specific portions of your program. You can then use #pragma info
resume to resume the same level of diagnostics later in the file.
You can also use #pragma checkout to suspend or resume diagnostics.
The OS/390 C/C++ Users Guide describes the INFO option.
pragma
inline
noinline
( function )
%&
IPA Considerations
The compiler uses the IPA Link control file directive in the following cases:
v If you specify both the #pragma noinline directive and the IPA Link control file
inline directive for a function
v If you specify both the #pragma inline directive and the IPA Link control file
noinline directive for a function
251
#pragma
Example
CBC3RABE:
/* this example shows how #pragma inline may be used */
#pragma csect(code,"MYCFILE")
#pragma csect(static,"MYSFILE")
#pragma options(INLINE)
#include <stdio.h>
#include <stdlib.h>
static int (writerecord) (int, char *);
#pragma inline (writerecord)
int main()
{
int chardigit;
int digit;
printf("Enter a digit\n");
chardigit = getchar();
digit = chardigit - '0';
if (digit < 0 || digit > 9)
{
printf("The digit you entered is not between 1 and 8\n");
exit(99);
}
switch(digit)
{
case 0:
writerecord(0, "entered 0");
break;
case 1:
writerecord(1, "entered 1");
break;
default:
writerecord(9, "entered other");
}
252
#pragma
}
}
return 0;
isolated_call
The #pragma isolated_call directive lists functions that do not alter data objects
visible at the time of the function call. In the following syntax diagram, identifier is a
primary expression that can be an identifier, operator function, conversion function,
or qualified name:
,
%% # pragma isolated_call ( '
identifier
%&
The pragma must appear before calls to the functions in the identifier list. You must
declare the identifiers that are listed before using them in the pragma. They must
be of type function, or a typedef of function. If a name refers to an overloaded
function, all variants of that function declared before the pragma are marked as
isolated calls.
The pragma informs the compiler that none of the functions listed has side effects.
For example:
v Accessing a volatile object
v Modifying an external object
v Modifying a file
Otherwise, you can consider calling a function that does any of the above to be
side effects.
Consider any change in the state of the run-time environment a side effect. Passing
function arguments by reference is one side effect that OS/390 C/C++ allows. In
general, however, functions with side effects can give incorrect results when listed
in #pragma isolated_call directives.
Marking a function as isolated indicates to the optimizer that external and static
variables cannot be changed by the called function. It also indicates that references
to storage can be deleted from the calling function where appropriate. Do not
specify a function that calls itself or relies on local static storage. Listing such
functions in the #pragma isolated_call directive can give unpredictable results.
When a function is marked as isolated, the compiler can make more optimistic
assumptions about what variables the function modifies. The compiler may move
function calls to functions that are flagged as isolated to a different location in the
code or even remove them entirely.
253
#pragma
The following example routines shows you when to use the #pragma isolated_call
directive (routine addmult). It also shows you when not to use it (routines same and
check):
#include <stdio.h>
#include <math.h>
int addmult(int op1, int op2);
#pragma isolated_call(addmult)
/* This routine is a good candidate to be flagged as isolated as its */
/* result is constant with constant input and it has no side effects. */
int addmult(int op1, int op2) {
int rslt;
temp = (op1-op2)/op1;
if (fabs(temp) < delta)
return 1;
else {
delta = delta / 2;
return 0;
}
IPA Considerations
If you specify this #pragma in your source code in the IPA Compile step, you cannot
override the effects of this #pragma on the IPA Link step.
langlvl
The #pragma langlvl directive selects the C or C++ language level for compilation.
%% #
254
pragma langlvl (
ansi
commonc
extended
saa
saal2
compat
%&
#pragma
You can only specify this pragma only once in a source file. It must appear before
any statements in a source file. The compiler uses predefined macros in the header
files to make declarations and definitions available that define the specified
language level.
The default language level is EXTENDED.
ansi
extended
commonc
saa
saal2
compat
255
#pragma
leaves
The #pragma leaves directive takes a function name, and specifies that the function
never returns to the instruction following a call to that function.
,
%% #
pragma leaves (
' function_name
%&
When enabled, the leaves pragma provides information to the compiler that enables
it to explore additional opportunities for optimization. Also see reachable on
page 268.
When you specify the LIBANSI compiler option, you tell the compiler that ANSI C
library function names refer to ANSI C library functions. These function names do
not refer to your own version of the library functions, which may have different
semantics. In this case, the compiler checks whether the longjmp family of functions
(longjmp, _longjmp, siglongjmp, and _siglongjmp) contain #pragma leaves. If the
functions do not contain this pragma directive, the compiler will insert this directive
for that function. This is not shown in the listing.
IPA Considerations
If you specify the #pragma leaves directive in your source code in the IPA compile
step, you cannot override the effects of this directive in the IPA link step.
linkage
The #pragma linkage directive identifies the entry point of modules that are used in
interlanguage calls.
%% #
pragma linkage (
identifier,
OS
FETCHABLE
PLI
COBOL
FORTRAN
, RETURNCODE
OS_DOWNSTACK
OS_UPSTACK
OS_NOSTACK
OS31_NOSTACK
REFERENCE
The identifier either identifies the name of the function that is to be the entry point
of the module. Or, it identifies a typedef that will be used to define the entry point.
In C++, you accomplish this by using extern "linkage-type" when declaring an
identifier, for example,
extern "FORTRAN" void f();
extern "COBOL"
void g();
256
%&
#pragma
The #pragma linkage directive also designates other entry points within a program
that you can use in a fetch operation.
The following are the linkage entry points:
FETCHABLE
OS
PLI
COBOL
FORTRAN
|
|
|
|
|
|
|
|
|
|
|
|
|
You can specify the RETURNCODE keyword with the FORTRAN keyword
for C programs only. OS/390 C/C++ does not support it for C++.
RETURNCODE indicates to the compiler that the routine named by
identifier is a FORTRAN routine, which returns an alternate return
code. It also indicates that the routine is defined outside the
compilation unit. You can retrieve the return code by using the
fortrc() function (refer to the OS/390 C/C++ Run-Time Library
Reference for more information). If the compiler finds the function
definition inside the compilation unit, it issues an error message.
Note that you can define functions outside the compilation unit,
even if you do not specify the RETURNCODE keyword.
|
|
|
OS_DOWNSTACK
|
|
|
|
|
|
OS_UPSTACK
257
#pragma
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OS_NOSTACK
|
|
|
OS31_NOSTACK
|
|
|
|
|
REFERENCE
You can use a typedef in a #pragma linkage directive to associate a specific linkage
convention with the typedef of a function.
typedef void func_t(void);
#pragma linkage (func_t,OS)
In the example, the #pragma linkage directive associates the OS linkage convention
with the typedef func_t. This typedef can be used in C declarations wherever a
function type specifies the type function of OS linkage type.
For further information about writing ILC applications and compiling with the
XPLINK option, please refer to the chapter on communicating with XPLINK - ILC
between XPLINK and Assembler in OS/390 Language Environment Writing
Interlanguage Applications.
|
|
|
|
longname
The #pragma longname directive specifies that the compiler is to generate
not-truncated and mixed case names in the object module that is produced by the
compiler. These names can be up to 1024 characters in length.
%% #
258
pragma
longname
nolongname
%&
#pragma
If you use the #pragma longname directive for an OS/390 C or C++ program, you
must either use the binder to produce a program object in a PDSE, or you must use
the prelinker. The binder, IPA Link step, and prelinker support the long name
directory that is generated by the Object Library utility for autocall.
If you specify the NOLONGNAME compile option, the compiler ignores the #pragma
longname directive. If you specify the LONGNAME compile option, the compiler ignores
the #pragma nolongname.
Note: The OS/390 C compiler defaults to the NOLONGNAME compile option, and the
OS/390 C++ compiler defaults to the LONGNAME compile option.
Under OS/390 C, if you specify the ALIAS compile option, the compiler creates a
NAME control statement, but no ALIAS control statements. You can use the OS/390 C
Object Library Utility to create a library of object modules with a long name directory
which supports autocall of long name symbols.
If you have more than one preprocessor directive, #pragma longname may be
preceded only by #pragma filetag, #pragma chars, #pragma langlvl, and #pragma
target. Some directives, such as #pragma variable and #pragma linkage are
sensitive to the name handling.
For OS/390 C++, you must specify #pragma longname and #pragma nolongname
before any code. Otherwise, the compiler issues a warning message.
If you use #pragma map to associate an external name with an identifier, the external
name is produced in the object module. That is, #pragma map has the same
behavior with or without the #pragma longname directive.
The #pragma nolongname directive directs the compiler to generate truncated and
uppercase names in the object module produced by the compiler. When the
#pragma nolongname directive is specified, only functions that do not have C++
linkage are given truncated and uppercase names. More details on external name
mapping are provided in the section, map. Also, if you have more than one
preprocessor directive, #pragma nolongname must be the first one.
If you specify either #pragma nolongname or the NOLONGNAME option, and this results
in mapping of two different source code names to the same object code name, the
compiler will not issue an error message.
IPA Considerations
You must specify either the LONGNAME compile option or the #pragma longname
preprocessor directive for the IPA Compile step (unless you are using the c89
utility). Otherwise, you receive an unrecoverable compiler error.
map
The #pragma map directive tells the compiler to convert all references to an identifier
to name.
#pragma map is a OS/390 C/C++ directive and an addition to SAA standard. If you
use the #pragma map directive, the C/C++ name in the source file is not visible in the
object deck. The map name represents the object in the object deck.
259
#pragma
%&
identifier
name
The external name that the compiler binds to the given object or
function. If the name is longer than 8 characters, you must use the
binder and specify the LONGNAME compile option.
The directive can appear anywhere within a single compilation unit. It can appear
before any declaration or definition of the named object or function.
You should enclose name in double quotation marks. The maximum length for
external names is eight characters, unless the LONGNAME compile option is specified.
The compiler keeps it as specified on the #pragma map directive in mixed case. It
must not conflict with the name in another #pragma map or #pragma csect directive.
|
|
The map name is an external name, thus you must not use it in the source file to
reference the object. If you use the map name in the source file to access the
corresponding object, the compiler treats it as a new identifier.
The compiler produces an error message if you give more than one map name to
an identifier. Two different identifiers can have the same map name.
The compiler resolves the identifiers appearing in the directive, including any type
names used in the prototype argument list. The compiler resolves them as though
the directive had appeared at file scope, independent of its actual point of
occurrence.
For example:
extern "C" int func(int);
#pragma map(func, "funcnam1")
// maps ::func
260
%% #
pragma map
% (
identifier
func_or_op_identifier (
argument_list )
name
%&
identifier
func_or_op_identifier
argument_list
name
#pragma
The directive can appear anywhere within a single compilation unit. It can appear
before any declaration or definition of the named object, function, or operator. The
compiler resolves the identifiers appearing in the directive, including any type
names used in the prototype argument list. It resolves them as though the directive
had appeared at file scope, independent of its actual point of occurrence.
Note: The map name is not affected by the CONVLIT or the ASCII compiler options.
For example:
int func(int);
class X
{
public:
void func(void);
#pragma map(func, "funcname1")
// maps ::func
#pragma map(X::func, "funcname2") // maps X::func
};
In
v
v
v
v
C++, you should not use #pragma map to map the following:
C++ Member functions
Overloaded functions
Objects generated from templates
Functions with C++ linkage, or builtin linkage
Such mappings override the compiler-generated names, which could cause IPA Link
or binder errors.
IPA Considerations
The use of the #pragma map directive for variables will inhibit the global coalescing
optimization of these variables during the IPA Link step.
margins
The #pragma margins directive specifies the margins in the source file that are to be
scanned for input to the compiler. You cannot specify columns (m,n) for OS/390
C++. The #pragma nomargins directive specifies that the entire input source record is
to be scanned for input to the compiler.
#pragma margins is a OS/390 C/C++ directive and an addition to the SAA Standard.
pragma
margins ( m
nomargins
%&
pragma
margins
nomargins
%&
In the syntax diagram, you can specify the following parameters for OS/390 C:
m
The first column of the source input that contains a valid C program. The
value of m must be greater than 0, and less than 32761.
Chapter 10. Preprocessor Directives
261
#pragma
Also, m must be less than or equal to the value of n.
n
The last column of the source input that contains a valid C program. The
value of n must be greater than 0, and less than 32761.
You can assign an asterisk (*) to n. The asterisk indicates the last column
of the input record. For example, if you specify #pragma margins(8,*), the
compiler scans from column 8 to the end of the record for input source
statements.
You can use #pragma margins and #pragma sequence together. If they
reserve the same columns, #pragma sequence has priority and it reserves
the columns for sequence numbers. For example, assume columns 1 to 20
are reserved for the margin, and columns 15 to 25 are reserved for
sequence numbers. In this case, the margin will be from column 1 to 14,
and the columns reserved for sequence numbers will be from 15 to 25.
For more information on the #pragma sequence directive, refer to sequence
on page 270.
The margin setting specified by the #pragma margins directive applies only to the
source file or include file in which it is found. It has no effect on other #include files.
The #pragma margins and the #pragma nomargins directives come into effect on the
line following the directive. They remain in effect until the compiler encounters
another #pragma margins or #pragma nomargins directive, or until the compiler
reaches the end of the file.
If you use the compile options MARGINS or NOMARGINS with the #pragma margins or
#pragma nomargins directives, the #pragma directives override the compile options.
The compile option specified will be in effect up to, and including, the #pragma
margins or #pragma nomargins directive.
For OS/390 C++, the #pragma margins specifies that columns 1 through 72 in the
input record are to be scanned for input to the compiler. The input file can have
fixed or variable record length. The compiler ignores any text in the source input
that does not fall within the range.
For OS/390 C, the default setting is MARGINS(1,72) for fixed-length records, and
NOMARGINS for variable-length records. For OS/390 C++, the default is NOMARGINS.
262
#pragma
See inline (C Only) - also see noinline on page 251 for more information. For more
information on how to use #pragma noinline, refer to the section on Optimizing
Code in the OS/390 C/C++ Programming Guide.
IPA Considerations
If you use either the #pragma inline or the #pragma noinline directive in your
source, you can later override them with an appropriate IPA Link control file
directive during the IPA Link step. For example:
v If you specify both the #pragma noinline directive and the IPA Link control file
inline directive for a function.
v If you specify both the #pragma inline directive and the IPA Link control file
noinline directive for a function.
options (C Only)
The #pragma options directive specifies a list of compile options that are to be
processed as if you had typed them on the command line or on the CPARM
parameter of the IBM-supplied cataloged procedures.
,
%% #
pragma options (
'
' option
%&
The only compile options that are allowed on a #pragma options directive are:
AGGREGATE|NOAGGREGATE
ARCHITECTURE
GONUMBER|NOGONUMBER
INLINE|NOINLINE
OBJECT|NOOBJECT
SERVICE|NOSERVICE
TEST|NOTEST
XREF|NOXREF
Note:
ALIAS|NOALIAS
CHECKOUT|NOCHECKOUT
HWOPTS|NOHWOPTS1
LIBANSI|NOLIBANSI
OPTIMIZE|NOPTIMIZE
SPILL|NOSPILL
UPCONV|NOUPCONV
ANSIALIAS|NOANSIALIAS
DECK|NODECK
IGNERRNO|NOIGNERRNO
MAXMEM|NOMAXMEM
RENT|NORENT
START|NOSTART
TUNE|NOTUNE
The compiler accepts the HWOPTS|NOHWOPTS option, but you should use the
ARCHITECTURE option instead.
1
For a detailed description of these options refer to the OS/390 C/C++ Users Guide.
If you use a compile option that contradicts the options that are specified on the
#pragma options directive, the compile option overrides the options on the #pragma
options directive.
If you specify an option more than once, the compiler uses the last one you
specified.
IPA Considerations
You cannot specify the IPA compile-time option for #pragma options.
Refer to the OS/390 C/C++ Users Guide for descriptions of how different compile
options affect IPA processing.
263
#pragma
option_override
|
|
|
|
With the #pragma option_override directive, you can specify optimization with more
granularity in your applications. Specifically, this pragma defines subprogram (C
function, C++ method) specific options that override those specified by the
command line options when performing optimizations for code and data in that
subprogram. This enables finer control of program optimization.
|
|
|
|
|
|
|
|
One use of this directive is to isolate coding errors that occur only under
optimization.
|
|
|
The subprogram-specific SPILL option allows you to specify large spill values for
specific functions, while allowing the remaining subprograms to have smaller
values.
|
|
|
% (
pragma option_override
function_name '
option
%&
4. This pragma directive maintains compatiblity with the AIX platform, even though the compiler options supported on the OS/390 and
AIX platforms are not the same. Thus, the option syntax for this directive is different from the OS/390 C/C++ command line option
syntax for the same option. Within this directive, options are grouped by category. OPT here signifies optimization-related options.
Within the category are the actual options. The optimization-related options are LEVEL (equivalent to the command line option
OPTIMIZE) and STRICT (equivalent to the command line option STRICT). This syntax attempts to be sufficiently platform-neutral such
that this directive is portable between different platforms.
264
#pragma
%% OPT (
COMPACT
LEVEL ,
SPILL ,
STRICT
,YES
,NO
0
1
2
size
%&
,YES
,NO
In the above syntax diagram, option translates to the following equivalent OS/390
C/C++ option settings:
option_override Value
COMPACT
COMPACT
COMPACT, YES
COMPACT
COMPACT, NO
NOCOMPACT
LEVEL, 0
OPT(0)
LEVEL, 1
OPT(1)
LEVEL, 2
OPT(2)
SPILL, size
SPILL(size)
STRICT
STRICT
STRICT, YES
STRICT
STRICT, NO
NOSTRICT
To use the LEVEL suboption, you must specify a non-zero optimization level for your
program, otherwise, the compiler ignores it. All other cases are meaningful,
including increasing the optimization level.
The #pragma option_override directive only affects functions that are defined in the
compile unit. The pragma directive can appear anywhere in the compilation unit.
That is, it can appear before or after the function definition, before or after the
function declaration, before or after the function has been referenced, and inside or
outside the function definition.
Specifying this directive only affects the setting of the options you have specified.
Notice that option can be enclosed in double quotation marks, so the options are
not subject to macro expansion.
Following is an example of how you might use this directive. Suppose you compile
the following code fragment containing the functions foo() and faa() using OPT(1).
Since it contains the #pragma option_override(faa, "OPT(LEVEL, 0)"), function
faa() will not be optimized.
foo(){
.
.
.
Chapter 10. Preprocessor Directives
265
#pragma
}
#pragma option_override(faa, "OPT(LEVEL, 0)")
faa(){
.
.
.
}
IPA Considerations
You cannot specify the IPA compile-time option for #pragma option_override.
|
|
|
|
|
During IPA Link processing, subprogram-specific options will be used to control IPA
Link-time optimizations, as well as program partitioning. They will be retained, even
if the related IPA Link command line option is specified.
|
|
Refer to the OS/390 C/C++ Programming Guide for descriptions of how different
subprogram-specific compile options affect IPA processing.
pack
The #pragma pack directive specifies the alignment rules to use for the structures,
unions, and classes that follow it. The C compiler performs packing on definitions if
you specify keyword _Packed and on declarations if you specify #pragma pack. The
C++ compiler does not support keyword _Packed, so it can only perform packing on
declarations. This means that the packing applies to type-specifiers and not
declarators. Prior to using this pragma directive, you should understand the
alignment rules for structures in Alignment of Structures on page 114 and
Alignment of Nested Structures on page 114, and for unions in Alignment of
Unions on page 119.
%% #
pragma pack (
1
2
4
full
packed
twobyte
reset
%&
where:
full
packed
twobyte
reset
The #pragma pack directive packs all structures and unions that follow it in the
program along a boundary specified in the directive. It continues to pack until
another #pragma pack directive changes the packing boundary. The #pragma pack
266
#pragma
directive does not apply to forward declarations of structures or unions. For
example, in the following code fragment, the alignment for struct S is full. This is
the rule when the declaration list is declared:
#pragma pack(packed)
struct S;
#pragma pack(full)
struct S { int i, j, k; };
The compiler packs declarations or types. This is different from the _Packed
keyword in OS/390 C, where packing is also performed on definitions. For
portability, you should use #pragma pack instead of the _Packed keyword.
The #pragma pack directive does not have the same effect as declaring a structure
as _Packed. The _Packed keyword removes all padding between structure members,
while the #pragma pack directive only specifies the boundaries to align the members.
If you are porting code from other platforms that contain #pragma pack directives or
packed data, consider using the PORT compiler option to increase the syntax
checking for the #pragma pack directive in your code. This option will allow you to
adjust the error recovery action the compiler takes if the # pragma pack is
incompatible with the OS/390 C/C++ # pragma pack. For more information on using
the PORT option, see the OS/390 C/C++ Users Guide.
page (C Only)
The #pragma page directive skips the number of pages that are specified by pages
of the generated source listing. If you do not specify pages, it starts the next page.
%% #
pragma page (
pages
%&
pagesize (C Only)
The #pragma pagesize directive sets the number of lines per page to n for the
generated source listing.
%% #
pragma pagesize (
%&
The default page size is 60 lines. The minimum page size that you should set is 25.
IPA Considerations
This #pragma has the same effect on the IPA Compile step as it does on a regular
compilation. It has no effect on the IPA Link step.
pragma priority (
%&
267
#pragma
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.
OS/390 C/C++ reserves the first 1024 priorities (INT_MIN to INT_MIN + 1023) for use
by the compiler and its libraries. The priority value that is specified applies to all
run-time static initialization in the current compilation unit.
OS/390 C/C++ constructs any global object declared before another object in a file
first. Use #pragma priority to specify the construction order of objects across files.
To ensure that the objects are always constructed from top to bottom in a file, the
compiler enforces a restriction. This restriction ensures that the priority specified for
all objects before and all objects after it is at that priority until the next #pragma.
reachable
The #pragma reachable directive takes a function name, and declares that the point
in the program after that function can be the target of a branch from some unknown
location. That is, you can reach the instruction after the specified function from a
point in your program other than the return statement in the named function.
,
%% #
pragma reachable (
' function_name
%&
When enabled, the reachable pragma provides information to the compiler that
enables it to explore additional opportunities for optimization.
Unlike the leaves pragma, the reachable pragma is required by the compiler
optimizer whenever the instruction following the call may receive control from some
program point other than the return statement of the called function. If this condition
is true and reachable is not specified, then the subprogram containing the call
should not be compiled with OPT(1), OPT(2) or IPA. Also see leaves on page 256.
|
|
|
|
|
When you specify the LIBANSI compiler option, you tell the compiler that that you
are using the system C runtime library, and not your own version of the library. In
this case, the compiler checks whether the setjmp family of functions (setjmp,
_setjmp, sigsetjmp, and _sigsetjmp) contain #pragma reachable. If the functions do
not contain this pragma, the compiler assumes that the pragma is specified.
IPA Considerations
If you specify the #pragma reachable directive in your source code in the IPA
compile step, you cannot override the effects of this directive in the IPA link step.
If you specify the LIBANSI compile option for any compilation unit in the IPA compile
step, the compiler generates information which indicates the setjmp() family of
functions contain the reachable status. If you specify the NOLIBANSI option for the
IPA link step, the attribute remains in effect.
runopts
The #pragma runopts directive specifies a list of runtime options that OS/390 C/C++
uses at execution time.
268
#pragma
,
%% #
pragma runopts (
'
' option
%&
Specify your #pragma runopts directive in the compilation unit that contains main. If
more than one compilation unit contains a #pragma runopts directive, unpredictable
results can occur. The #pragma runopts directive only affects compilation units
containing main().
If a suboption to #pragma runopts is not a valid C token, you can surround the
suboptions to #pragma runopts in double quotes. For example, use:
#pragma runopts ( " RPTSTG(ON) TEST(,,,VADTCPIP&1.2.3.4:*) " )
instead of:
#pragma runopts ( RPTSTG(ON) TEST(,,,VADTCPIP&1.2.4.3:*) )
Refer to target (C Only) on page 272 and the OS/390 C/C++ Users Guide for
information about how #pragma target and the TARGET compile-time option affect
#pragma runopts. Refer to the OS/390 Language Environment Programming Guide
for descriptions of specific run-time options.
IPA Considerations
This #pragma only affects the IPA Compile step if you specify the OBJECT suboption
of the IPA compiler option.
The IPA Compile step passes the effects of this directive to the IPA Link step.
Consider if you specify ARGPARSE|NOARGPARSE, EXECOPS|NOEXECOPS, PLIST, or
REDIR|NOREDIR either on the #pragma runopts directive or as a compile-time option
on the IPA Compile step, and then specify the compile-time option on the IPA Link
step. In this case, you override the value that you specified on the IPA Compile
step.
If you specify the TARGET compile-time option on the IPA Link step, it has the
following effects on #pragma runopts:
v It overrides the value you specified for #pragma runopts(ENV). If you specify
TARGET(LE) or TARGET(), the compiler sets the value of #pragma runopts(ENV) to
MVS. If you specify TARGET(IMS), the compiler sets the value of #pragma
runopts(ENV) to IMS.
v It may override the value you specified for #pragma runopts(PLIST). If you
specify TARGET(LE) or TARGET(), and you specified something other than HOST for
#pragma runopts(PLIST), the compiler sets the value of #pragma runopts(PLIST)
to HOST. If you specify TARGET(IMS), the compiler sets the value of #pragma
runopts(PLIST) to IMS.
For #pragma runopts options other than those that are listed above, the IPA Link
step follows these steps to determine which #pragma runopts value to use:
1. The IPA Link step uses the #pragma runopts specification from the main()
routine, if the routine exists.
2. If no main() routine exists, the IPA Link step follows these steps:
269
#pragma
a. If you define the CEEUOPT variable, the IPA Link step uses the #pragma
runopts value from the first compilation unit that it finds that contains
CEEUOPT.
b. If you have not defined the CEEUOPT variable in any compilation unit, the
IPA Link step uses the #pragma runopts value from the first compilation unit
that it processes.
The sequence of compilation unit processing is arbitrary.
To avoid problems, you should specify #pragma runopts only in your main() routine.
If you do not have a main() routine, specify it in only one other module.
sequence
The #pragma sequence directive specifies the section of the input record that is to
contain sequence numbers. The #pragma nosequence directive specifies that the
input record does not contain sequence numbers.
#pragma sequence is an OS/390 C/C++ directive and an addition to the SAA
Standard.
pragma
sequence ( m ,
nosequence
%&
pragma
sequence
nosequence
%&
In the syntax diagram you can specify the following parameters for OS/390 C:
m
The sequence setting specified by the #pragma sequence directive applies only to
the file (source file or include file) that contains it. The setting has no effect on other
270
#pragma
#include files in the file. The sequence number area specified on the #pragma
sequence directive comes into effect on the line following the directive. It remains in
effect until it encounters another #pragma sequence or a #pragma nosequence
directive or until it reaches the end of the file.
If you use the compile-time options SEQUENCE|NOSEQUENCE with the #pragma sequence
or #pragma nosequence directives, the #pragma directive overrides the compile
options. The compile option is in effect up to, and including, the #pragma sequence
or the #pragma nosequence directive.
For OS/390 C++, the #pragma sequence directive defines that columns 73 through
80 of the input record (fixed or variable length) contain sequence numbers. You
cannot specify columns (m,n). The default compile option for OS/390 C++ is
NOSEQUENCE.
For OS/390 C, the default setting is SEQUENCE(73,80) for fixed-length records, and
NOSEQUENCE for variable length records.
skip (C Only)
The #pragma skip directive skips the specified number of lines in the generated
source listing. The value of lines must be a positive integer less than 255. If you
omit lines, the compiler skips one line.
%% #
pragma skip (
lines
%&
strings
The #pragma strings directive sets the storage type for strings. It specifies that the
compiler can place strings into read-only memory or must place strings into
read/write memory.
%% #
pragma strings (
writable
writeable
readonly
%&
IPA Considerations
During the IPA Link step, the compiler compares the #pragma strings specifications
for individual compilation units. If it finds differences, it treats the strings as if you
specified #pragma strings(writeable) for all compilation units.
subtitle (C Only)
The #pragma subtitle directive places the text that is specified by subtitle on all
subsequent pages of the generated source listing.
271
#pragma
%% #
subtitle "
%&
target (C Only)
The #pragma target directive specifies the operating system or run-time
environment for which OS/390 C/C++ creates the object.
Note: You cannot specify the release suboptions (that is, OSV1R2 and so on) using
the #pragma target directive as you can with the TARGET compile option. See
the OS/390 C/C++ Users Guide for information on the TARGET option.
%% #
pragma target (
LE
IMS
%&
IMS
If you have more than one preprocessor directive, the only #pragma directives that
can precede #pragma target are #pragma filetag, #pragma chars, #pragma langlvl,
and #pragma longname.
Specifying #pragma target() or #pragma target(LE) has the following effects on
#pragma runopts(ENV) and #pragma runopts(PLIST):
v If you did not specify values for #pragma runopts(ENV) or #pragma
runopts(PLIST), the compiler sets the #pragmas to #pragma runopts(ENV(MVS))
and #pragma runopts(PLIST(HOST)).
v If you did specify values for #pragma runopts(ENV) or #pragma runopts(PLIST),
the values do not change.
Specifying #pragma target(IMS) has the following effects on #pragma runopts(ENV)
and #pragma runopts(PLIST):
v If you did not specify values for #pragma runopts(ENV) or #pragma
runopts(PLIST), the compiler sets the #pragmas to #pragma runopts(ENV(IMS))
and #pragma runopts(PLIST(OS)).
v If you did specify values for #pragma runopts(ENV) or #pragma runopts(PLIST),
the values do not change.
IPA Considerations
This #pragma only affects the IPA Compile step if you specify the OBJECT suboption
of the IPA compiler option.
The IPA Compile step passes the effects of this #pragma directive to the IPA Link
step.
If you specify different #pragma target directives for different compilation units, the
IPA Link step uses the ENV and PLIST information from the compilation unit
containing main(). If there is no main(), it uses information from the first compilation
unit it finds. If you specify the TARGET compile option for the IPA Link step, it
overrules the #pragma target directive.
272
#pragma
title (C Only)
The #pragma title directive places the text that is specified by title on all
subsequent pages of the generated source listing.
%% #
pragma title (
"
title "
%&
variable
The #pragma variable directive specifies that OS/390 C/C++ is to use the named
external object in either a reentrant or non-reentrant fashion. If an object is marked
as RENT, its references or its definition will be in the writable static area that is in
modifiable storage. If an object is marked as NORENT, its references or definition is in
the code area and is in potentially read-only storage.
%% #
pragma variable (
identifier ,
RENT
NORENT
%&
NORENT does not apply to, and has no affect on, program variables with static
storage class. OS/390 C/C++ always includes these variables with the writable
static variables. Variables are reentrant by default for C++ so that RENT has no
affect.
The #pragma variable directive is an OS/390 C/C++ directive and an addition to the
SAA Standard.
You can use the ROCONST and RENT compiler options so that const variables are not
placed into the Writeable Static Area instead of using the #pragma
variable(var_name, NORENT) directive.
If the specification for a const variable in a #pragma variable directive conflicts with
the ROCONST option, the pragma directive takes precedence over the compiler option,
and the compiler issues an informational message.
Refer to the section on Reentrancy in OS/390 C/C++ in the OS/390 C/C++
Programming Guide for more information about reentrancy.
wsizeof
The #pragma wsizeof directive toggles the behavior of the sizeof operator between
that of the C and C++ compilers prior to and including the C/C++ MVS/ESA Version
3 Release 1 product, and the OS/390 C/C++ feature. As explained below, the
difference occurs only when using sizeof on function return types. Other behaviors
of sizeof remain the same.
Specify the pragma as follows:
%% #pragma wsizeof (
ON
RESUME
%&
When using the sizeof operator, the C and C++ compilers prior to and including
C/C++ MVS/ESA Version 3 Release 1, returned the size of the widened type
Chapter 10. Preprocessor Directives
273
#pragma
instead of the original type for function return types. For example, in the following
code fragment, using the older compilers, i has a value of 4.
char foo();
i = sizeof foo();
Using the OS/390 C/C++ compiler, i has a the value of 1, which is the size of the
original type, char.
After a #pragma wsizeof(on) is encountered in a source program, all subsequent
sizeof operators return the widened size for function return types. The behavior
prior to the #pragma wsizeof(on), which can be the old or current behavior, is
saved. OS/390 C/C++ reinstates this saved behavior when it encounters a matching
#pragma wsizeof(resume). The saving action works on a stack. That is, a resume
reinstates the most recently saved state as the following example demonstrates:
/* Normal behavior of sizeof to start with.
/*
... some code here ...
*/
*/
#pragma wsizeof(on)
/* (1) old behavior of sizeof
...
#pragma wsizeof(on)
/* (2) old behavior of sizeof
...
#pragma wsizeof(resume) /* matches (2)
/* still old behavior of sizeof
...
#pragma wsizeof(resume) /* matches (1)
/* normal behavior of sizeof
*/
*/
*/
*/
*/
*/
The compiler will match on and resume throughout the entire compile unit. That is,
the effect of a #pragma wsizeof(on) can extend beyond a header file. Ensure the
on and resume pragmas are matched in your compile unit.
Note: Dangling the resume pragma leads to undefined behavior. The effect of an
unmatched on pragma can extend to the end of the source file.
Use the wsizeof pragma in old header files, where you require the old behavior of
the sizeof operator. By guarding the header file with a #pragma wsizeof(on) at the
start of the header, and a #pragma wsizeof(resume) at the end, you can use the old
header file with new applications.
The WSIZEOF compile option has exactly the same effect as inserting a #pragma
wsizeof(on) at the beginning of the source file. If another #pragma wsizeof exists in
the source code, OS/390 C/C++ toggles the behavior of the sizeof operator, as
described above.
You can use the WSIZEOF compile option to save editing your source when you want
the old behavior of the sizeof operator for your entire source file.
Refer to the OS/390 C/C++ Users Guide for information on the WSIZEOF compile
option.
IPA Considerations
During the IPA Compile step, the size of each function return value is resolved
during source processing. The IPA Compile and Link steps do not alter these sizes.
The IPA object code from compilation units with different wsizeof settings is merged
together during the IPA Link step.
274
275
276
277
CBC3X10C
// In this example, class X is equivalent to struct Y
class X
{
int a; //
public:
int
};
struct Y
{
int f() {
private:
int
};
private by default
f() { return a = 5; }; // public member function
return a = 5; };
// public by default
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. In the following
example, main() has access to the members of X even though X is declared as
using the keyword class:
CBC3X10D
// This example declares a structure, then declares a class
// that is an object of the structure.
#include <iostream.h>
struct x {
int a;
int b;
} ;
class x X;
void main() {
X.a = 0;
X.b = 1;
cout << "Here are a and b " << X.a << " " << X.b << endl;
}
Aggregate Classes
An aggregate class is a class that has no user-defined constructors, no private or
protected members, no base classes, and no virtual functions.
Initializers on page 129 describes the initialization of aggregate classes.
278
class
struct
union
class_name
:base_class
member_list
%&
Class Names
A class name is a unique identifier that becomes a reserved word within its scope.
Once a class name is declared, it hides other declarations of the same name within
the enclosing scope.
Consider a class name that is declared in the same scope as a function,
enumerator, or object with the same name. You can refer to that class by using an
elaborated type specifier. In the following example, the elaborated type specifier is
used to refer to the class print. This class 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 on page 282.
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.
279
CBC3X10B
// This example illustrates a typedef used to simplify
// a nested class name.
#include <iostream.h>
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();
}
For more information on nested classes, see Nested Classes on page 283
/* definition of class X */ };
/* definition of struct Y */ };
/* definition of union Z */ };
Then you can declare objects of each class type. Remember that classes,
structures, and unions are all types of C++ classes.
void main()
{
X xobj;
Y yobj;
Z zobj;
}
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
280
Y yobj;
X xobj;
class X xobj;
// valid
// error, class name X is hidden
// valid
For more information on hidden names, see Scope of Class Names on page 282.
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 that are
of class S in a single declaration:
class S { /* ... */ };
//
.
//
.
//
.
void main()
{
S S,T; // declare two objects of class type S
}
You can also declare references to classes, pointers to classes, and arrays of
classes. For example:
class X { /* ... */ };
struct Y { /* ... */ };
union Z { /* ... */ };
void main()
{
X xobj;
X &xref = xobj;
Y *yptr;
Z zarray[10];
}
You can assign or pass objects of class types that are not copy restricted as
arguments to functions. Functions can also return these objects. For more
information, see Copy Restrictions on page 331.
For more information on objects, see Objects on page 74. Initialization by
Constructor on page 327 discusses initialization of classes.
281
CBC3X10E
// This example shows the scope of class names.
class x { int a; };
x xobject;
//
//
//
//
redefine x to be a function
use class-key class to define
a pointer to the class type x
as the function argument
//
//
//
//
void main()
{
class x* xptr;
xptr = &xobject;
x(xptr);
You can use an elaborated type specifier in the declaration of objects and functions.
See Class Names on page 279 for an example.
You can also use an elaborated type specifier in the incomplete declaration of a
class type to reserve the name for a class type within the current scope.
struct second
{
first* oneptr;
first one;
int x, y;
282
If you declare a class with an empty member list, it is a complete class declaration.
For example:
class X;
class Z {};
class Y
{
public:
X yobj;
};
Z zobj;
Chapter 12. C++ Class Members and Friends on page 287 describes class
member lists.
Nested Classes
You declare a nested class 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. This
includes 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 by using a qualified type name. You can also access
member functions f() and g() of the nested class nested. Qualified type names
allow you to define a typedef to represent a qualified class name. Then you can
use the typedef with the :: (scope resolution) operator to refer to a nested class or
class member.
The following example demonstrates this:
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; };
283
// define a typedef
// use typedef with ::
. . .
Local Classes
You declare a local class 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.
For example:
int x;
void f()
{
static int y;
int x;
extern int g();
// global variable
// function definition
//
//
//
//
//
//
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;
//
.
//
.
//
.
}
Define member functions of a local class 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.
For more information about inline functions, see Inline Member Functions on
page 290.
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();
int g() {return 0;}
static int a;
}
//
284
};
int b;
. . .
//
//
//
//
//
//
Here, function f() takes an argument of type s::T. However, the following
declarations, which reverse the member order of s, 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.
285
286
Related Information
v Chapter 11. C++ Classes on page 277
v Chapter 15. C++ Inheritance on page 335
v Chapter 14. Special C++ Member Functions on page 317
287
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.
However, you cannot place explicit initializers inside the class definition.
If you declare an array as a nonstatic class member, you must specify all the array
dimensions.
OS/390 C++ always processes the bodies of member functions after the definition
of their class is complete. Consequently, the body of a member function can refer to
the name of the class that owns it, even if this requires information about the class
definition.
288
In this example, the inline function f() is permitted to make use of the size of class
Y. See Inline Member Functions on page 290 for more information.
Member Functions
Member functions are operators and functions that are declared as members of a
class. Member functions do not include operators and functions that are declared
with the friend specifier. Refer to these as friends of a class. For more information,
see Friends on page 301.
The definition of a member function is within the scope of its enclosing class.
OS/390 C++ analyzes the body of a member function after the class declaration so
that the member function body can use members of that class. 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()
{return a+b+c;};
private:
int a,b,c;
};
289
Member Functions
Virtual Functions on page 351 describes virtual functions in more detail. Abstract
Classes on page 355 describes pure virtual functions.
Consider when you declare an inline function without the inline keyword and do
not define it in the class member list. In this case, you cannot call the function
before you define it. In the above example, you cannot call f() until after its
definition.
Inline member functions have internal linkage. Noinline member functions have
external linkage.
For more information, see C++ Inline Functions on page 194.
290
Member Functions
template. If instantiating a class template, OS/390 C++ only instantiates the function
templates whose instantiations will be used by the resulting template class.
For more information about member function templates, see Member Function
Templates on page 369.
Member Scope
You can define member functions and static members outside their class
declaration if you have already declared but not defined them in the class member
list. By instantiating the class for nonstatic data members, you define the members.
The declaration of a static data member is not a definition. The declaration of a
member function is a definition if you also provide the body of the function.
Whenever the definition of a class member appears outside of the class declaration,
you must qualify the member name by the class name. Use the :: (scope
resolution) operator.
The following example defines a member function outside of its class declaration.
CBC3X11A
// This example illustrates member scope.
#include <iostream.h>
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<<endl;
}
291
Member Scope
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
The search of the enclosing classes, including inherited members, is demonstrated
in the following example:
class
class
class
class
A { /* ... */
B { /* ... */
C { /* ... */
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)
Note: When OS/390 C++ searches the containing classes, it only searches the
definitions of the containing classes and their base classes. It does not
search the scope that contains the base class definitions (global scope, in
this example).
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 does not associate 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.
You can use pointers to members that are used as the following example
demonstrates:
292
Pointers to Members
CBC3X11B
// This example illustrates pointers to members.
#include <iostream.h>
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
Use the pointer to member operators, .* and ->*, 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.
For more information, see C++ Pointer-to-Member Operators (.* >*) on page 160.
293
CBC3X11C
// This example illustrates the this pointer
#include <iostream.h>
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.
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.
CBC3X11D
// This example uses class members without the this pointer.
#include <string.h>
#include <iostream.h>
#define BUFLN 100
class X
{
int len;
char *ptr;
public:
int GetLen()
{ return len; }
char * GetPtr()
{ return ptr; }
X& Set(char *);
X& Cat(char *);
X& Copy(X&);
void Print();
};
294
//
//
//
//
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);
Static Members
You can declare class members by using the storage-class specifier static in the
class member list. All the objects of a class in a program share only one copy of the
static member. When you declare an object of a class that contains 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 track 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:
295
Static Members
class X
{
public:
static int i;
};
int X::i = 0; // definition outside class declaration
//
.
//
.
//
.
You can access a static member from outside of its class only if you declare it with
the keyword public. You can then access the static member by qualifying the class
name by using the :: (scope resolution) operator. In the following example, you can
refer to the static member f() of class type X as X::f():
class X
{
public:
static int f();
};
//
.
//
.
//
.
void main ()
{
X::f();
}
For more information on the storage-class specifier static, see static Storage
Class Specifier on page 83.
CBC3X11E
// This example illustrates access to static
// members with class access operators.
#include <iostream.h>
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;
296
Static Members
xobj1.Set_Show(11);
xobj1.Set_Show(11,22);
xobj1.Set_Show(xobj2, 44);
When you access a static member through a class access operator, OS/390 C++
does not evaluate the expression to the left of the . or -> operator.
You can refer to a static member independently of any association with a class
object because there is only one static member that is shared by all objects of a
class. A static member can exist, even if you have not declared any objects of its
class.
When you access a static member, OS/390 C++ does not evaluate the expression
that you use to access the member. 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.
CBC3X11F
// This example shows that the expression used to
// access a static member is not evaluated.
class X
{
public:
static int i;
};
int X::i = 10;
X f() { /* ... */ }
void main ()
{
int a;
a = f().i;
}
int
int
int
int
int
int
int
int
int
i;
j;
k;
l;
m;
n;
p;
q;
r;
Chapter 12. C++ Class Members and Friends
297
Static Members
static int s;
static int f() { return 0; }
int a;
public:
C() { a = 0; }
};
int
int
int
int
int
int
C c;
C::i =
C::j =
C::k =
C::l =
C::s =
C::r =
class Y : private C {} y;
int
int
int
int
C::m
C::n
C::p
C::q
=
=
=
=
Y::f();
Y::r;
y.r; // error
y.f(); // error
The initializations of C::p and C:: cause errors because y is an object of a class
that is derived privately from C. Its members are not accessible to members of C.
You can only have one definition of a static member in a program. If you do not
initialize a static data member, OS/390 C++ assigns a zero default value to it.
Local classes cannot have 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().
CBC3X11G
// This example shows the declaration, initialization,
// use, and scope of a static data member.
#include <iostream.h>
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;
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();
298
Static Members
CBC3X11H
// This example illustrates a static member function f().
#include <iostream.h>
class c {
static void f() { cout << "Here is i"
<< i << endl;}
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();
}
You cannot declare a static member function 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.
Member Access
Member access determines if a class member is accessible in an expression or
declaration. Note that accessibility and visibility are independent. The scoping rules
of C++ determines visibility. A class member can be visible and inaccessible at the
same time. This section describes how you control the access to the individual
underived class members by using access specifiers when you declare class
members in a member list.
299
Member Access
CBC3X10A
// This example illustrates class member access specifiers
#include <iostream.h>
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 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.
Access Specifiers
The three class member access specifiers have the following effect:
public class members
You can access them by any function, file, or class.
private class members
You can access them only by member functions and friends of the class in
which the member is declared.
protected class members
You can only access them by member functions and friends of the class in
which they are declared. You can also access them by member functions
and friends of classes derived with public or protected access from the
class in which you have declared the protected members. You can use the
access specifier, protected, for class members that are not base members.
300
Member Access
It is, however, equivalent to private unless it is used in a base class
member declaration, or in a base list. For more information, see Protected
Members on page 342.
The default access for an individual class member depends on the class key that is
used in the class declaration. Members of classes that are declared with the
keyword class are private by default. Members of classes that are 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.
Inherited Member Access on page 341 describes access for inherited members.
Member lists can include access specifiers as labels. Members that are 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.
The following example shows access specifiers in member lists.
class X
{
int a;
public:
void f(int);
int b;
private:
int c;
protected:
void g(int);
};
struct Y
{
int a;
public:
int b;
private:
void g(int);
int c;
};
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. Refer to functions that are declared with the friend specifier in a
class member list as friend functions of that class. Refer to classes that are
declared with the friend specifier in the member list of another class as friend
classes of that class.
You must define a class Y before you can declare any member of Y as a friend of
another class.
In the following example, the friend function print is a member of class Y. It
accesses the private data members a and b of class X.
301
Friends
CBC3X11I
// This example illustrates a friend function.
#include <iostream.h>
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);
}
CBC3X11J
// This example illustrates a friend class.
#include <iostream.h>
class X
{
public:
X() {a=1; b=2;}
//
private:
int a, b;
friend class F;
//
};
class F
{
public:
void print(X& x)
{
cout << "A is " << x.a
cout << "B is " << x.b
}
//
.
//
.
//
.
302
constructor
friend class
<< endl;
<< endl;
Friends
};
void main ()
{
X xobj;
F fobj;
fobj.print(xobj);
}
If the you have not previously declared the class, 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
};
//
.
//
.
//
.
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 that is
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, OS/390 C++ searches the body of the
function definition for unqualified names starting from the class that contains 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
};
Consider when the name of a friend class has been introduced before the friend
declaration. Then, the compiler searches for a class name that matches the name
of the friend class, beginning at the scope of the friend declaration. When 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.
303
Friends
The scope of a friend class name is the first nonclass enclosing scope. Consider
the following example:
class A {
class B { // arbitrary nested class definitions
friend class C;
};
};
If the friend function is a member of another class, you need to use the class
member access operators. For example:
class A
{
public:
int f() { /* ... */ }
};
class B
{
friend int A::f();
};
Any classes you derive from a base class do not inherit friends of that base class.
For more information about friend scope, see Scope of Class Names on page 282.
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. In addition, you can only access the protected members of a
class through member functions of a class, or classes that are derived from that
class.
Access specifiers do not affect friend declarations.
For more information on access, see Member Access on page 299.
304
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 you call an overloaded function, OS/390 C++
compares the types of the actual arguments with the types of the formal arguments.
Thus, it selects the correct function.
Consider a function print, which displays an int. The following example
demonstrates that you can overload this function 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.
CBC3X12A
// This example illustrates function overloading.
#include <iostream.h>
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*)
}
Declaration Matching
Two function declarations are identical if all of the following are true:
v They have the same function name
v They are declared in the same scope
v They have identical argument lists
When you declare a function name more than once in the same scope, the
compiler interprets the second declaration of the function name as follows:
Copyright IBM Corp. 1996, 2000
305
Overloading Functions
v If the return type, argument types, and number of arguments are identical for the
two declarations, the compiler considers that the second declaration is the same
as the first.
v If only the return types of the two function declarations differ, the second
declaration is an error.
v If either the argument types or number of arguments of the two declarations
differ, the function is an overloaded function.
306
Argument Matching
An ambiguous match occurs when the actual arguments of the function call match
more than one overloaded function.
The matching of arguments includes performing standard and user-defined
conversions on the arguments in order to match the actual arguments with the
formal arguments. OS/390 C++ only performs a single user-defined conversion in a
sequence of conversions on an actual argument. In addition, OS/390 C++ performs
the best-matching sequence of standard conversions on an actual argument. The
best-matching sequence is the shortest sequence of conversions between two
standard types. For example, you can shorten the following conversion:
int -> float -> double
In the above example, the compiler allows the conversion from int to double.
Trivial conversions, that are described in Trivial Conversions on page 308, do not
affect the choice of conversion sequence.
// matches f(int);
// 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 matching of
arguments for overloaded functions or operators.
Chapter 13. C++ Overloading
307
Argument Matching
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.
See The this Pointer on page 293 for information on the this pointer. See Dot
Operator (.) on page 142 and Arrow Operator (>) on page 142 for information
on the class-member access operators.
Trivial Conversions
The compiler cannot distinguish between functions if they have the same name and
arguments which differ only in that one is declared as a reference to a type, and the
other is that type. You cannot have two functions with the same name and with
arguments that differ only in this respect. Because the following two declarations
cannot be distinguished, the second one causes an error:
double
//
//
//
double
Functions with the same name and arguments can be distinguished only if they
have following differences::
v One is a pointer or reference, and the other is a pointer to const or const
reference.
v One is a pointer or reference, and the other is a pointer to volatile or volatile
reference.
To find a best match of arguments, functions with a volatile or const match (not
requiring a trivial conversion) are better than those that have a volatile or const
mismatch.
For more information on conversions, see Standard Type Conversions on
page 167 and User-Defined Conversions on page 325.
Overloading Operators
You can overload one of the standard C++ operators by redefining it to perform a
particular operation when you apply it to an object of a particular class. Overloaded
operators must have at least one argument that has class type. OS/390 C++ calls
an overloaded operator an operator function. You declare it with the keyword
operator that precedes the operator itself. Overloaded operators are distinct from
overloaded functions. Like overloaded functions however, you distinguish them by
the number and types of operands you used with the operator.
You can overload any of the following operators:
+
!
|=
<=
( )
=
&=
>=
[ ]
*
<
|=
&&
new
/
>
<<
||
delete
%
+=
>>
++
|
=
<<=
&
*=
>>=
,
|
/=
==
>*
308
%=
!=
>
Overloading Operators
Consider the standard + (plus) operator. When you use this operator with operands
of different standard types, the operators have slightly different meanings. For
example, C++ does not implement the addition of two integers 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 you apply them to class types. The
following example defines a class that is called complx to model complex numbers.
The example redefines the + (plus) operator in this class to add two complex
numbers.
CBC3X12B
// This example illustrates overloading the plus (+) operator.
#include <iostream.h>
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+()
}
&
When an overloaded operator is a member function, C++ matches the first operand
against the class type of the overloaded operator. It matches the second operand, if
one exists, 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. OS/390 C++ matches the first operand against the
first argument in the overloaded operator call. It matches the second operand, if
one exists, against the second argument in the overloaded operator call.
The argument-matching conventions and rules that are described in Argument
Matching in Overloaded Functions on page 306 apply to overloaded operators.
309
Overloading Operators
Usually, you invoke overloaded operators by using the normal operator syntax. You
can also call overloaded operators explicitly by qualifying the operator name. For
example, for the class complx, as described above, you can call the overloaded +
(plus) operator either implicitly or explicitly. The following example demonstrates
this:
CBC3X12C
// This example shows implicit and explicit calls
// to an overloaded plus (+) operator.
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+()
}
310
Overloading Operators
.*
::
?:
However, this depends on the declarations of the operator function. If you have
declared both forms of the operator function, argument matching determines which
interpretation OS/390 C++ uses.
For more information on standard unary operators, see Unary Expressions on
page 142.
311
or
operator*(x,y)
depending on the declarations of the operator function. If you have declared both
forms of the operator function, argument matching determines which interpretation
OS/390 C++ uses.
For more information on standard binary operators, see Binary Expressions on
page 152.
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)
}
312
You can provide default arguments and ellipses in the argument list for the function
call operator, unlike all other overloaded operators. For example:
class X
{
public:
X& operator() (int = 5);
};
//
.
//
.
//
.
For more information on the standard function call operator, see Function
Calls ( ) on page 140.
Overloaded Subscripting
An expression that contains the subscripting operator has the following syntax of
the form, and OS/390 C++ considers it a binary operator.:
identifier[ expression ]
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]
313
314
CBC3X12D
// This example illustrates an overloaded prefix increment operator.
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++();
operator++(y);
++y;
}
//
//
//
//
x.operator++
x.operator++
nonmember operator++
nonmember operator++
You can overload the postfix increment operator ++ for a class type by declaring a
nonmember function operator operator++() with two arguments. The first argument
has class type, and the second has 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:
CBC3X12E
// This example illustrates an overloaded postfix increment operator.
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++(0);
operator++(x,0);
//
//
//
//
x.operator++
default zero is supplied by compiler
x.operator++
nonmember operator++
315
316
317
Constructors
A constructor is a member function with the same name as its class. For example:
class X
{
public:
X();
//
.
//
.
//
.
};
You can use constructors to create and initialize objects of their class type.
Initialization by Constructor on page 327 describes the initialization of class objects
using constructors.
Default Constructors
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 your program needs one, the compiler creates a default
constructor, with public access, for that class. The compiler does not create a
default constructor for a class that has any constant members or reference type
members.
A constructor can have default arguments, like all functions. You can use them to
initialize member objects. If the call to the constructor supplies default values, you
can omit the trailing arguments in the expression list of the constructor. For more
information, see Default Arguments in C++ Functions on page 189. Note that if a
constructor has any arguments that do not have default values, it is not a default
constructor.
Copy Constructors
Use a copy constructor to make a copy of one class object from another class
object of the same class type. You call a copy constructor 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 your program needs one, the compiler
318
Constructors
creates a copy constructor, with public access, for that class. The compiler does not
create a copy constructor for a class if any of its members or base classes have an
inaccessible copy constructor.
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
};
In the above example, the compiler calls constructors for object in the following
order:
B1();
B1();
B2();
B3();
D();
//
//
//
//
//
319
Constructors
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. When OS/390 C++ constructs class B2, it calls the constructor
for class B1 in addition to B2s own constructor.
The second call to the constructor of B1 followed by the call to the constructor of B2
is part of the construction of B2.
For more information, see Construction Order of Derived Class Objects on
page 330.
Destructors
A destructor is a member function with the same name as its class that is prefixed
by a (tilde).
For example:
class X
{
public:
X();
X();
//
.
//
.
//
.
};
A destructor takes no arguments and has no return type. You cannot take its
address. You cannot declare destructors as const, volatile, or static. You can
declare a destructor as virtual or pure virtual. A union cannot have as a member
an object of a class with a destructor.
Use destructors to deallocate memory and do other cleanup for a class object and
its class members when you destroy the object. OS/390 C++ calls a destructor for a
class object when that object passes out of scope or you explicitly delete it.
320
Destructors
Class members that are class types can have their own destructors. Both base and
derived classes can have destructors, although destructors are not inherited.
Consider that 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. In that case,
OS/390 C++ generates a default destructor. The default destructor calls the
destructors of the base class and the members of the derived class. OS/390 C++
generates default destructors with default public access.
The compiler calls destructors in the reverse order to which it calls constructors:
1. It calls the destructor for a class object before it calls destructors for members
and bases.
2. It calls destructors for nonstatic members before calling destructors for base
classes.
3. It calls destructors for nonvirtual base classes before calling destructors for
virtual base classes.
When your program throws an exception for a class object with a destructor,
OS/390 C++ does not call the destructor for the temporary object that it throws until
your program passes control out of the catch block. For more information, see
Constructors and Destructors in Exception Handling on page 382.
OS/390 C++ calls destructors implicitly when an automatic or temporary object
passes out of scope. It also calls them implicitly at program termination for
constructed external and static objects. Destructors are invoked when you use the
delete operator for objects that are created with the new operator.
For example:
#include <string.h>
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()
}
Although you can use a destructor explicitly to destroy objects, you should not use
this method. If an object has been placed at a specific address by the new operator,
you can call the destructor of the object to destroy it. An explicitly called destructor
cannot delete storage.
321
Destructors
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
Free Store
Use free store to dynamically allocate 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. 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, one of the operator functions
operator new() or operator new[]() (if they have been declared) is called to create
the object. An operator new() or 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
<stddef.h>.
When you overload the new operator, you must declare it as a class member, that
returns type void*, with first argument size_t, as described above. You supply
additional arguments in the declaration of operator new() or operator new[]().
Use the placement syntax to specify values for these arguments in an allocation
expression.
The following example shows how to use the overloaded new and delete operators
and the overloaded new and delete vector operators.
#include <new.h>
#include <stdio.h>
char buff[10000];
char* cur=buff;
322
Free Store
class X {
public:
X() { printf("X constructed\n"); }
X() { printf("X destroyed\n"); }
};
main() {
// create, then delete different types of objects and
// arrays-of-objects
printf("New
int* flat =
printf("New
int* arr =
int\n");
new int;
array-of-int\n");
new int[2];
printf("New X\n");
X* x = new X;
printf("New array-of-X\n");
X* xArr = new X[2];
printf("Delete
delete[] xArr;
printf("Delete
delete x;
printf("Delete
delete[] arr;
printf("Delete
delete flat;
}
array-of-X\n");
X\n");
array-of-int\n");
int\n");
return(0);
The delete operator destroys an object that is created by the new operator. The
operand of delete must be a pointer returned by new. If you call delete for an
object with a destructor, OS/390 C++ invokes the destructor before it deallocates
the object.
If you destroy a class object with the delete operator, the operator function
operator delete() or operator delete[]() (if they have been declared) is called to
destroy the object. An operator delete() or operator delete[]() for a class is
Chapter 14. Special C++ Member Functions
323
Free Store
always a static member, even if it is not declared with the keyword static. Its first
argument must have type void*. Because operator delete() and operator
delete[]() have a return type void, they cannot return a value. They cannot be
virtual.
When you overload the delete operator, you must declare it as a class member,
returning type void. Its first argument must be 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() or operator delete[]() for a single class.
Overloading new and delete is described in Overloaded new and delete on
page 316.
The following example shows the declaration and use of the operator functions
operator new() and operator delete():
#include <stddef.h>
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
}
The result of trying to access a deleted object is undefined because the value of the
object can change after deletion.
Consider if you call new and delete for a class object that does not declare the
operator functions new and delete. Or, consider if you call them for a nonclass
object. In these cases, OS/390 C++ uses the global operators new and delete. The
global operators new and delete are provided in the C++ library.
Note: The C++ operators for allocating and deallocating arrays of class objects are
operator new[ ]()and operator delete[ ](). They are described in C++
new Operator on page 148 and C++ delete Operator on page 151.
Temporary Objects
It is sometimes necessary for the compiler to create temporary objects. It uses
these objects during reference initialization and during evaluation of expressions
that includes standard type conversions, argument passing, function returns, and
evaluation of the throw expression.
324
Temporary Objects
When the compiler creates a temporary object to initialize a reference variable, the
name of the temporary object has the same scope as that of the reference variable.
When it creates a temporary object during the evaluation of an expression, the
object exists until there is a break in the control flow of the program. If the compiler
creates a temporary object for a class with constructors, it calls the appropriate
(matching) constructor to create the temporary object.
When it destroys a temporary object and a destructor is available, the compiler calls
the destructor to destroy the temporary object. When you exit from the scope in
which the temporary object was created, the object 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 was destroyed earlier by a break in the flow of
control. For example, a temporary object that is created by a constructor initializer
for a reference member is destroyed on leaving the constructor.
The following example shows two expressions in which temporary objects are
constructed:
class Y
{
public:
Y(int)={ };
Y(Y&)={ };
Y()={ };
};
Y add(Y y) { return y; }
//
.
//
.
//
.
void main ()
{
Y obj1(10);
Y obj2 = add(Y(5));
obj1 = add(obj1);
}
The above example created a temporary object of class type Y to construct Y(5)
before passing it 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. OS/390 C++ creates a temporary object of class type Y when
the example passes obj1 to the function add(). Because obj1 has already been
constructed, the function add() constructs its return value into a temporary object.
The example then assigns this second temporary object to obj1 by using an
assignment operator.
Related Information
v
v
v
v
v
User-Defined Conversions
User-defined conversions allow you to specify object conversions with constructors
or with conversion functions. OS/390 C++ implicitly uses user-defined conversions
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.
Chapter 14. Special C++ Member Functions
325
User-Defined Conversions
There are two types of user-defined conversions:
v Conversion by constructor
v Conversion functions.
For more information, see Standard Type Conversions on page 167.
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.
For example:
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))
}
Conversion Functions
You can define a member function of a class that is called a conversion function. A
conversion function converts from the type of its class to another specified type.
%%
class ::
operator
const
volatile
conversion_type
*
&
function_body }
The conversion function specifies a conversion from the class type of which the
conversion function is a member, 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.
326
%&
User-Defined Conversions
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;
}
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.
OS/390 C++ implicitly applies only one user-defined conversion to a single value.
User-defined conversions must be unambiguous, or OS/390 C++ does not call
them.
If you declare a conversion function with the keyword const, the keyword does not
affect the function. Except, it does act as a tiebreaker when there is more than one
conversion function that you could apply. Specifically, if more than one conversion
function could be applied, OS/390 C++ compares all of these functions. If you
declare any of these functions with the keyword const, OS/390 C++ ignores const
for the purposes of this comparison. If one of these functions is a best match, it is
applied. If there is no best match, OS/390 C++ compares the functions again, but
this time it does not ignore const.
Initialization by Constructor
You must explicitly initialize a class object with a constructor or it must have a
default constructor. Explicit initialization by using a constructor is the only way,
except for aggregate initialization, to initialize nonstatic constant and reference class
members.
An aggregate is a class object that has no constructors, no virtual functions, no
private or protected members, and no base classes. Structures on page 107 and
Unions on page 114 describes aggregates.
Explicit Initialization
You can initialize class objects with constructors by using a parenthesized
expression list. The call to a constructor uses this list as an argument list to initialize
the class. You can also call a constructor with a single initialization value by using
the = operator. Because this type of expression is an initialization, not an
assignment, OS/390 C++ does not call the assignment operator function if one
exists. It uses this value 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.
The syntax for an initializer that explicitly initializes a class object with a constructor
is:
Chapter 14. Special C++ Member Functions
327
Initialization by Constructor
%%
(
=
expression )
expression
,
{ '
expression
%&
The following example shows the declaration and use of several constructors that
explicitly initialize class objects:
CBC3X13A
// This example illustrates explicit initialization
// by constructor.
#include <iostream.h>
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);
complx two = one;
=
=
=
=
=
1
1
3
0
5
im
im
im
im
im
=
=
=
=
=
0
0
4
0
0
Constructors can initialize their members in two ways. A constructor can use the
arguments you pass to it to initialize member variables in the constructor definition:
complx( double r, double i = 0.0) {re = r; im = i;}
328
Initialization by Constructor
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. You must use the second method to initialize base classes from within a
derived class to initialize constant and reference members, and members with
constructors.
identifier
class_name
( '
assignment_expression
%&
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);
// noinline 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. Consider in the above example, if you leave out the call
B2() in the constructor of class D (as shown below). In that case, a constructor
initializer with an empty expression list is automatically created to initialize B2. The
constructors for class D, that is shown above and below, result in the same
construction of a class D object.
Chapter 14. Special C++ Member Functions
329
Initialization by Constructor
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.
For example:
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();
//
int b;
private:
B4(int);
//
};
//
.
//
.
//
.
{ /* ... */ }
/* ... */ }
330
Initialization by Constructor
The following code fragment calls the constructor for class B1, before it initializes
the member d1. The value it passes 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)
};
Copy Restrictions
You cannot generate a default assignment operator for a class that has the
following:
v A nonstatic constant or a reference data member
v A nonstatic data member or base class whose assignment operator is not
accessible
v A nonstatic data member or base class with no assignment operator and for
which a default assignment operator cannot be generated
You cannot generate a default copy constructor for a class that has:
v A nonstatic data member or base class, whose copy constructor is not accessible
v A nonstatic data member or base class with no copy constructor and for which a
default copy constructor cannot be generated
Copy by Assignment
If you do not define an assignment operator and your code requires one, the
compiler defines a default assignment operator. If you do not define an assignment
operator and your code does not require one, the compiler declares a default
331
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 which the class type it is a member.
For more information on standard C and C++ assignment operators, see
Assignment Expressions on page 163. For more information on assignment
operator functions, see Overloaded Assignment on page 312.
Copy by Initialization
If you do not define a copy constructor and your program requires one, the compiler
creates a default copy constructor. If you do not define a copy constructor, and your
program does not require one, the compiler declares a default copy constructor but
does not define it. If a class defines a copy constructor, the compiler does not
generate a default copy constructor.
Use copy by initialization 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. However, all of its base classes and members
must have copy constructors that accept constant arguments, for example:
class B1
{
public:
B1(const B1&) { /* ... */ }
};
332
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. For more
information on copy constructors, see Constructors on page 318, and Initialization
by Constructor on page 327.
333
334
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, that includes 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.
Suppose that you have defined a shape class to describe and operate on geometric
shapes. Now suppose that 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, OS/390 C++ uses these redefined function implementations.
335
Inheritance
For example:
class shape
{
char* name;
int xpoint, ypoint;
public:
virtual void rotate(int);
virtual void draw();
void display() const;
};
class circle: public 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. The example declares member functions rotate() and draw() in class
shape with the keyword virtual. Consequently, you can provide an alternative
implementation for the member functions in class circle.
You can also provide an alternative implementation for the nonvirtual member
function display() in class circle. Suppose you manipulate an argument of type
circle using a pointer to shape, and you 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 calls the member function
that is 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 as follows.
When you treat the circle class as if it were a shape, the program uses the
implementations of the virtual functions rotate() and draw() that are defined in
class circle 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
Multiple inheritance allows you to create a derived class that inherits properties from
more than one base class.
For example, in addition to the above shape class, 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 your program derives the circle class from
both the shape and symbol classes, the circle class inherits properties from both
classes.
336
Inheritance
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 previous example, class circle inherits the members name, xpoint, ypoint,
display(), rotate(), and draw() from class shape. It also inherits the members
language, letter, number, write(), and meaning() from class symbol.
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.
337
Inheritance
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.
Polymorphism
Polymorphic functions are functions that you can apply to objects of more than one
type. C++ implements polymorphic functions in two ways:
v Overloaded functions are statically bound at compile time, as discussed in
Overloading Functions on page 305.
v C++ provides virtual functions. A virtual function is a function that you can call 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 you call a virtual function,
the compiler executes the function implementation that is associated with the object
for which you call the function. The implementation of the base class is only a
default that is used when the derived class does not contain its own
implementation.
Derivation
C++ implements inheritance 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.
Base lists do not allow incompletely declared classes.
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.
Consider the following example.
338
Derivation
CBC3X14A
// This example illustrates references
// to base class members.
class base
{
public:
int a,b;
};
class derived : public
{
public:
int c;
};
void main()
{
derived d;
d.a = 1;
//
d.b = 2;
//
d.c = 3;
//
base
base::a
base::b
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. 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.
Consider the following example.
CBC3X14B
// This example illustrates references to base class
// members with the scope resolution (::) operator.
#include <iostream.h>
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);
}
C++ Scope Resolution Operator (::) on page 138 describes the :: (scope
resolution) operator.
339
Derivation
You can manipulate a derived class object as if it was 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 that expects a pointer or reference to the base
class of D. You do not need to use an explicit cast to achieve this; the compiler
performs a standard conversion. 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 following example assigns d, a pointer to a derived class object, 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.
CBC3X14C
// This example illustrates how to make a pointer
// to a derived class point to a base class.
#include <iostream.h>
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 = &d;
// call base::display(base::name;)
bptr->display(bptr->name);
340
Derivation
,
% '
virtual
qualified_class_specifier
%&
public
private
protected
public
private
protected
virtual
The qualified class specifier must be a class that you have previously declared in a
class declaration, as Class Names on page 279 describes. The access specifiers
(public, private, and protected) are described in Member Access on page 299.
You can use the virtual keyword to declare virtual base classes. For more
information, see Virtual Base Classes on page 348.
The following example shows the declaration of the derived class D and the base
classes V, B1, and B2. The class B1 is derived from class V and is a base class for D.
Consequently, it is both a base class and a derived class.
class
class
class
class
V { /* ... */ };
B1 : virtual public V { /* ... */ };
B2 { /* ... */ };
D : public B1, private B2 { /* ... */ };
In this example, class A has a private member a, and class B has a public member
a. The example derives class C from both A and B. C does not have access to A::a,
but a in the body of f() or B:: can still resolve to either A::a or B::a. For this
reason, a is ambiguous in the body of f().
Chapter 15. C++ Inheritance
341
Protected Members
If you publicly derive a class from a base class, members and friends of any
classes that are derived from that class can access a protected static base class
member. Members and friends of any classes derived from that base class can
access a protected nonstatic base class member by using one of the following
items:
v A pointer to a directly or indirectly derived class
v A reference to a directly or indirectly derived class
v An object of a directly or indirectly derived class
If you derive a class privately from a base class, all protected base class members
become private members of the derived class.
The access specifier protected is also described in Access Specifiers on
page 300.
You can use both a structure and a class as base classes in the base list of a
derived class declaration. If you declare the base class with the keyword class, its
default access specifier in the base list of a derived class is private. If you declare
the base class with the keyword struct, its default access specifier in the base list
of a derived class is public.
342
Members and friends of a class can implicitly convert a pointer to an object of that
class to a pointer to either:
v A direct private base class
v A protected base class (either direct or indirect)
Access Declarations
You can restore access to members of a base class by using an access
declaration. It allows you to change the access to a public member in a private or
protected base class back to public. You can also change the access to a protected
member in a private base class back to protected. Use the base class member
qualified name in the public or protected declarations of the derived class to adjust
access.
You only use access declarations to restore base class access. You cannot use
them to do the following tasks:
v
v
v
v
343
CBC3X14D
// This example illustrates using access declarations
// to restore base class access.
#include <iostream.h>
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
OS/390 C++ restores the access of b 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. This is in addition to the
inherited members, b, c, and bprint() that the example declares 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.
Use access declarations only to adjust the access to a member in a base class.
The derived class can directly or indirectly inherit the base class in which an access
declaration appears.
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
};
344
// error
If you use an access declaration to adjust the access to an overloaded function, the
function adjusts the access for all functions with that name in the base class.
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 that is 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. Member Access on page 299 describes
access rules. These scopes are:
Call scope
Reference scope
For example, in the following code the reference scope for member is the type of
aobject, that is class type A:
CBC3X14E
// This example illustrates access resolution.
class B { public: int member; };
class A : B {}
void main()
{
A aobject;
aobject.member = 10;
}
// declaration
// declaration
// declaration
// expression
Choose reference scope by simplifying the expression (or declaration) that contains
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. Select
reference scope as follows:
1. Consider if the member is qualified with . (dot) or -> (arrow). If it is, the
reference scope is the type of the object that is immediately to the left of the .
or -> operator closest to the member. OS/390 C++ treats unqualified members
as if they are qualified with this->.
345
346
Access Summary
The following example demonstrates inherited member access rules.
CBC3X14F
// This example illustrates 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);
B::b = 10;
d = 5 ;
}
};
class D2 : private B
{
int e;
public:
B::c;
void h(int i) { d = 5; }
};
void main( )
{
int i= 1;
D1 d1;
D2 d2;
d1.a = 5;
d2.b = 10;
//
//
//
//
//
//
//
//
//
//
//
d2.c = 5;
d2.B::c = 5;
d1.c = 5;
d1.d = 5;
d2.e = 10;
d1.g(i);
d1.h(i);
d2.h(i);
Multiple Inheritance
You can derive a class from more than one base class. Multiple inheritance means
to derive a class from more than one direct base class.
In the following example, classes A, B, and C are direct base classes for the derived
class X:
Chapter 15. C++ Inheritance
347
Multiple Inheritance
B
X
class
class
class
class
A
B
C
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 on page 327.
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:
B2
B3
D
class
class
class
class
L { /* ... */ };
// indirect base class
B2 : public L { /* ... */ };
B3 : public L { /* ... */ };
D : public B2, public B3 { /* ... */ }; // valid
In the above example, class D inherits the indirect base class L once through class
B2 and once through class B3. 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 by 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.
348
Multiple Inheritance
virtual in front of the base class specifiers in the base lists of classes B1 and B2.
This indicates that only one class L, shared by class B1 and class B2, exists.
For example:
L
B2
B1
D
class
class
class
class
class
};
};
*/ }; // 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:
B2
B3
B1
D
class
class
class
class
class
V { /* ... */ };
B1 : virtual public V { /* ... */ };
B2 : virtual public V { /* ... */ };
B3 : public V { /* ... */ };
D : public B1, public B2, public B3 { /* ... */ };
In the above example, class D has two objects of class V. One is shared by classes
B1 and B2, and one is shared through class B3.
Multiple Access
If an inheritance graph contains virtual base classes, you can access a name that
can be reached through more than one path, through the path that gives the most
access.
For example:
class
class
class
class
{
349
Multiple Inheritance
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.
CBC3X14G
// This example illustrates ambiguous base classes.
class B1
{
public:
int i;
int j;
int g( );
};
class B2
{
public:
int j;
int g( );
};
//
.
//
.
//
.
class D : public B1, public
{
public:
int i;
};
void main ()
{
D dobj;
D *dptr = &dobj;
dptr -> i = 5;
dptr -> j = 10;
dptr->B1::j = 10;
dobj.g( );
dobj.B2::g( );
}
350
B2
//
//
//
//
//
valid,
error,
valid,
error,
valid,
D::i
ambiguous reference to j
B1::j
ambiguous reference to g( )
B2::g( )
Multiple Inheritance
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
}
Virtual Functions
In C++, the mechanism of virtual functions supports dynamic binding. 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 the derived class may override
the function implementation. 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 re-implement a virtual member function, like any member function, in any
derived class. When you make a call to a virtual function, the implementation that
OS/390 C++ executes depends on the type of the object for which it is called. If you
call a virtual member function for a derived class object and the function is
351
Virtual Functions
redefined in the derived class, your program executes the definition in the derived
class. In this case, the redefined derived class function overrides the base class
function.
Overriding occurs even if the access to the function is through a pointer or
reference to the base class. Calling a virtual function with a pointer that has base
class type but points to a derived class object, calls the member function of the
derived class. However, calling a nonvirtual function with a pointer that has base
class type calls the member function of the base class, regardless of whether or not
the pointer points to a derived class object.
For example:
class B
{
public:
virtual int f();
virtual int g();
int h();
};
class D : public B
{
public:
int f();
int g(char*);
int h();
};
//
.
//
.
//
.
void main ()
{
D d;
B* bptr = &d;
bptr->f();
bptr->h();
bptr->g();
d.g();
d.g("string");
// hides B::g()
//
//
//
//
//
If the argument types or the number of arguments of the two functions are different,
the functions are considered different. In addition, 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. However, the following restrictions apply:
v The return type of the overridden virtual function must be a pointer or a reference
to a class B.
v The return type of the overriding virtual function must be a pointer or a reference
to a class D.
v The return types of the overridden and overriding virtual functions must both be
pointers to classes B and D respectively. Or, they must both be references to
classes B and D respectively.
v Class B must be an accessible base class of class D. Also, with the OS/390 C++
compiler, class D must not have multiple or virtual inheritance.
For more information, see Function Return Values on page 191.
352
Virtual Functions
A virtual function cannot be global or static. 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. Friends on page 301 describes friends.
If you declare a function as virtual in its base class, you can still access it directly
by using the :: (scope resolution) operator. In this case, OS/390 C++ suppresses
the virtual function call mechanism, and uses the function implementation that is
defined in the base class. If you do not redefine a virtual member function in a
derived class, a call to that function uses the function implementation that is defined
in the base class.
A virtual function must be one of the following:
v Defined
v Declared pure
v Defined and declared pure
A base class that contains one or more pure virtual member functions is an abstract
class. For more information, see Abstract Classes on page 355.
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() attempt to override
V::f(). The compiler does not allow this attempt because it is not possible to
decide which function to call if a D object is referenced with a pointer to class V. The
above example illustrates this point. The compiler flags this situation as an error, as
only one function can override a virtual function.
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
353
Virtual Functions
A and one in class B. If the compiler allows the declaration of class D, 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 = &d;
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.
354
Virtual Functions
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
}
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
};
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
}
A function that is declared pure typically has no definition and cannot be executed.
Attempting to call a pure virtual function that has no implementation is undefined;
however, such a call does not cause an error. You cannot create objects of an
abstract class, as the above example demonstrates.
Note: Because destructors are not inherited, a virtual destructor that is declared
pure must have a definition.
Virtual member functions are inherited. Consider 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. In that case, the derived class itself is an abstract
class. Any attempt to create an object of the derived class type produces an error.
For example:
class AB // abstract class
{
public:
virtual void f()= 0; // pure virtual member function
};
class D2: public AB
{
int a,b,c;
Chapter 15. C++ Inheritance
355
Abstract Classes
public:
void g();
};
//
.
//
.
//
.
void main ()
{
D2 d;
// error, cannot declare an object of abstract class D2
}
356
Templates Overview
The syntax for a template is:
argument declaration
StaticDataMember
>
%&
357
Templates Overview
The template arguments (within the < and > delimiters) specify the types and the
constants within the template that you must specify when the template is
instantiated.
Given the following template:
template<class L> class Key
{
L k;
L* kptr;
int length;
public:
Key(L);
// ...
};
The following table shows what the classes Key<int>, Key<char*>, and Key<mytype>
look like:
class Key<int> i;
class Key<char*> c;
class Key<mytype> m;
class Key<int>{
int k;
int * kptr;
int length; public:
Key(int);
// ... };
class Key<char*> {
char* k;
char** kptr;
int length;
public:
Key(char*);
// ... };
Class Key<mytype> {
mytype k;
mytype* kptr;
int length; public:
Key(mytype);
// ... };
CBC3X15A
// This example shows a template declaration
// with default initializers.
358
Templates Overview
#include <stdio.h>
template <class T, int i=1> class X
{
public:
T s;
X(int j=4);
int val(T&)
{
return i;
};
};
template <class T, int i> X<T,i>::X(int j):s(i){
printf("i=%d
j=%d\n",i,j);
}
void main()
{
X<int>
myX(2);
X<int,3> myX2(4);
}
File stack.h
#ifndef _STACK_TPL_H
#define _STACK_TPL_H
template<class T>
class stack
{
private:
T* v;
T* p;
int sz;
public:
stack( int );
stack();
void push( T );
};
#endif
File stackdef.h
#include "stack.h"
template<class T> stack<T>::stack( int s )
{
Chapter 16. C++ Templates
359
v = p = new T[sz=s];
To instantiate a stack of 50 ints, you would declare the following in each source file
that requires it:
stack<int> intStack(50);
For method 1, each source file that uses the template should include both stack.h
and stackdef.h.
For method 2, every source file should include stack.h. However, 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 PDS. You can use the TEMPINC
option to set your own TEMPINC PDS.
You should use the LSEARCH option to include the two PDSs, USR.INCLUDE.C and
USR.INCLUDE.H, which contain the stack.c and stack.h files, respectively. The
syntax for this is:
LSEARCH('USR.INCLUDE.+')
For information about include files, and the TEMPINC and LSEARCH options, see the
OS/390 C/C++ Users Guide.
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.
Note the distinction between the terms class template and template class:
Class template
Template class
A template definition is identical to any valid class definition that the template might
generate, except for the following:
v The following syntax precedes the class template definition:
template < template-argument-list >
360
Class Templates
v 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).
v 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
Using the type specifier 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. OS/390 C++ allows only one template declaration that
contains the class definition.
You can instantiate the class template by declaring a template class. If the template
class member function definitions are not inline, you have to define them. When you
instantiate a template class, its argument list must match the argument list in the
class template declaration.
template <class L,class T> class key
{
//
.
//
.
//
.
};
template <class L> class vector
{
//
.
//
.
//
.
};
void main ()
{
class key <int, vector<int> >; // instantiate template
}
Note: When you have nested template argument lists as in the above example,
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 >.
Any of the techniques that are used to access ordinary class member objects and
functions can access objects and functions of individual template classes. For
example, assume you have this class template:
template<class T> class vehicle
{
public:
vehicle() { /* ... */ }
// constructor
vehicle() {};
// destructor
T kind[16];
T* drive();
static void roadmap();
// ...
};
361
Class Templates
vehicle<char> bicycle; // instantiates the template
In the above example, the constructor, the constructed object, and the member
function drive() can be accessed with any of the following. (This assumes the
standard header file <string.h> is included in the program file.)
constructor
object bicycle
function drive()
char* n = bicycle.drive();
function roadmap()
vehicle<char>::roadmap();
//
//
//
//
//
//
//
//
//
If you use a template class before defining the corresponding class template, the
compiler issues an error. The compiler considers a class name, with the
appearance of a template class name, 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 compiler does not compile the definition of a class template until it requires the
definition of a template class. At that point, it compiles the class template definition
by using the argument list of the template class to instantiate the template
arguments. The compiler flags any errors in the class definition at this time. If the
compiler never requires the definition of a class template, it does not compile it. In
this case, the compiler will not flag any errors in the definition.
362
Class Templates
In this example, the template argument size becomes a part of the template class
name. It creates an object of such a template class with both the type arguments of
the class and the values of any additional template arguments.
From this template, you can create an object x and its corresponding template class
with arguments double and size=200. Use a value as the second template
argument:
myfilebuf<double,200> x;
The objects that are created by these expressions are identical because the
template arguments evaluate identically. The value 200 in the first expression 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.
Note: Arguments that contain the < symbol or the > symbol must be enclosed in
parentheses. This prevents it from being parsed as a template argument list
delimiter when you use it as a relational operator or a nested template
delimiter. For example, the arguments in the following definition are valid:
myfilebuf<double, (20>10)> x;
// valid
363
Class Templates
The following definition, however, is not valid because it interprets the
greater than operator (>) as the closing delimiter of the template argument
list:
myfilebuf<double, 20>10> x;
// error
If the template arguments do not evaluate identically, the objects that are created
are of different types:
myfilebuf<double,200> x;
myfilebuf<double,200.0> y;
//
//
//
//
The instantiation of y fails because the value 200.0 is of type double, and the
template argument is of type int.
Consider the following two objects:
myfilebuf<double, 128> x
myfilebuf<double, 512> y
These two objects belong to separate template classes, and referencing either of
these objects later with myfilebuf<double> 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<int i> class C
{
public:
int k;
C() { k = i; }
};
Again, these two declarations refer to distinct classes because the values of their
nontype arguments differ.
Using the applicable template class name can define the type for which the
template class is inappropriate. Assuming the inappropriately defined type is stocks,
you can redefine the class portfolio<stocks> as follows:
364
Class Templates
class portfolio<stocks>
{
double capital;
stocks yield;
// ...
};
You can define an explicit specialization of a template class before declaring the
class template. In particular, you can define a template class such as
portfolio<stocks> before defining its class template.
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. You must use all
type arguments in a function template in the argument list, or in the class qualifier
for the function name. You do not need to explicitly specify the type of a template
function argument when you call the template function. In this respect, a template
function differs from a template class.
Note the distinction between the terms function template and template function:
Function template
Template function
Assuming that 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;
The above example generates the following template function to resolve the call:
int approximate(float,float)
365
Function Templates
3. Tries ordinary overloading resolution for functions already present. This does not
include template functions, unless you have explicitly declared such functions by
using a function declaration.
A call to a template function causes an error, and OS/390 C++ does no overloading
if the following conditions are true:
v The only available functions for a call are template functions.
v These functions would require nontrivial conversions for the call to succeed.
v You have not explicitly declared these functions.
In the case of the approximate() function template, 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))
{ /* ... */ }
366
Function Templates
#include <string.h>
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 following function call invokes the above explicitly defined
function, and no template function is generated:
approximate("String A","String B");
Explicit definition has the same effect on template overloading resolution as explicit
declaration. (See Overloading Resolution for Template Functions on page 365 for
more information.) Assume that you explicitly define a template function as follows:
int approximate(double a, double b) { /* ... */ }
When compiled and run, the program prints the number 4 to standard output. This
indicates that the compiler uses the explicitly defined function to resolve the call to
f().
You must define each template, whether of a class or of a function, at most once
within a compilation unit. The same applies to an explicitly defined template class or
function. You can declare function templates and class templates many times.
Chapter 16. C++ Templates
367
Function Templates
You declare a template class by using its name. You declare a template function if
any of the following situations apply:
v A function whose name matches a function templates name you have declared,
and the compiler can generate an appropriate template function.
v A function whose name matches a function templates name you have called,
and the compiler can generate an appropriate template function.
v A function whose name matches a function templates name you have called,
and you have explicitly defined the template function.
v You take the address of a template function in such a way that instantiation can
occur. This means that the pointer to function must supply a return type and
supply argument types that can be used to instantiate the template function.
OS/390 C++ instantiates or generates a template function provided the function is
not explicitly defined elsewhere in the program, if you reference the function in the
following ways:
v Your program declares the function.
v It calls the function.
v It takes the the address of the function.
When your program instantiates a template function, OS/390 C++ compiles the
body of the function template by using the template argument list of the template
class to instantiate the template arguments. The compiler flags any errors in the
function definition at this time. If the function template never generates a template
function, OS/390 C++ does not compile it. In this case, the compiler will not flag any
errors in the function definition.
range> class ex
// valid
// error
// error
C++ requires this explicit naming convention to ensure that it can generate the
appropriate class.
A template function chooses the name of its function template, and the particular
function to resolve a given template function call. It determines the name and the
function 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). The call, min(af, bf), is
effectively a call to min(float a, float b):
CBC3X15B
// This example illustrates a template function.
template<class T> T min(T a, T b)
{
if (a < b)
return a;
368
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;
}
369
Use member function templates to instantiate any functions that are not explicitly
generated. If you have both a member function template and an explicit definition,
OS/390 C++ uses the explicit definition.
Do not use the template argument in a constructor name. For example:
template<class L> class
{
Key();
Key( L );
Key<L>( L );
};
Key
// default constructor
// constructor taking L by value
// error, <L> implicit within class template
The declaration Key<L>(L) is an error because the constructor does not use the
template argument. Assuming that removing the offending line corrected this class
template, you can define a function template for the class templates constructor:
// Constructor contained in function template:
template<class L>
Key<L>::Key(int) { /* ... */ }
// valid, constructor template argument assumed template<class L>
Key<L>::Key<L>(int) { /* ... */ }
/* error, constructor template argument <L> 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. Consider
the following definition:
Key<L>::Key(int) { /* ... */ }
The above definition is valid because Key<L> (with template argument) refers to the
class, while Key(int) { /* ... */ } refers to the member function.
370
You can also define a static data member of a template class using a template
definition at file scope. For example:
template <class T> class key
{
public:
static T x;
};
template <class T> T key<T> ::x; // template definition
371
The definitions of static variables and objects must be instantiated at file scope. If
the classes Key<int> and Key<double> are instantiated from this template, and no
template definitions exist, the following static data members must be explicitly
defined at file scope, or an error occurs:
int Key<int>::k, Key<int>::length, Key<double>::length
int* Key<int>::kptr;
double Key<double>::k;
double* Key<double>::kptr = 0;
372
373
%% try { '
statement
} catch {
...
declarator
abstract declarator
{ ' statement
%&
assignment expression
%&
374
The following example throws an object for the purpose of exception handling:
.
.
.
int input=0;
cout << "Enter a number between 1 and 10:";
cin >> input;
2. Function calls that you anticipate might produce an exception must be enclosed
in braces and preceded by the keyword try. A try statement in a caller
anticipates exceptions.
3. You must code one or more catch blocks immediately following the try block.
Each catch block identifies what type or class of objects it can catch:
a. If the object that is thrown matches the type of a catch expression, OS/390
C/C++ passes control to that catch block.
b. If the object that is thrown does not match the first catch block, OS/390
C/C++ searches subsequent catch blocks for a matching type.
c. If it cannot find a match, OS/390 C/C++ continues the search in all enclosing
try blocks, and then in the code that called the current function.
d. If no match is found after all try blocks are searched, a call to terminate()
is made.
For information on the default handlers of uncaught exceptions, see Special
Exception Handling Functions on page 386.
Notes:
1. You can throw any object if you can copy and destroy it in the function from
which the throw occurs.
2. You should never throw exceptions 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 if OS/390 C/C++
cannot generate a copy of it. For example:
class B {
public:
B();
B(B&);
};
The catch block causes an error because the compiler does not know the type of
the object that is thrown at compile time. It assumes that the type of the thrown
Chapter 17. C++ Exception Handling
375
Transferring Control
C++ implements the termination model of exception handling. In the termination
model, when your program throws an exception, 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 your program throws an exception, it passes control ou of the throw
expression, and out of the try block that anticipated the exception. It passes control
to the catch block whose exception type matches the object that is 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. It 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 that
contains the catch block.
Consider if your program throws an exception, and no try block is active, or if a try
block is active and the catch block exception declaration does not match the object
thrown. In this case, OS/390 C/C++ issues a call to terminate(), which in turn calls
abort to terminate the program. The abort C library function is defined in the
standard header file <stdlib.h>.
For more information on terminate(), see Special Exception Handling Functions
on page 386.
The following example illustrates the basic use of try, catch, and throw. The
program prompts for numerical input and determines the inputs 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, the program throws an
exception, and the catch block catches the exception. If the input is nonzero, the
reciprocal is printed to standard output.
CBC3X16A
// This example illustrates the basic use of
// try, catch, and throw.
#include <iostream.h>
#include <stdlib.h>
class IsZero { /* ... */ };
376
Transferring Control
void ZeroCheck( int i )
{
if (i==0)
throw IsZero();
}
void main()
{
double a;
This example provides a simple illustration of formal exception handling. You could
make it more efficient by using informal exception handling.
Another example of exception handling under C++ is shown below. The testeh()
routine is called from the mainfunction. testeh() first throws the integer 6, which is
handled by a catch clause within testeh().
Next, it throws a short int, k. There are no catch clauses in testeh() which can
handle a short int. The testeh() routine ends, and destructors are called for the
objects it created. Control passes back to the main function. It contains a catch
clause which can handle the thrown short int. The example calls destructors for
the remaining objects as the program ends.
CBC3X16F
// This is a more extensive example of
// C++ exception handling.
#include <iostream.h>
int testeh(void);
class A {
int i;
public:
A(int j) { i = j; cout << "A ctor: i=" << i << '\n';}
A() { cout << "A dtor: i=" << i << '\n';}
};
class B {
char c;
public:
B(char d) { c = d; cout << "B ctor: c=" << c << '\n'; }
B() { cout << "B dtor: c=" << c << '\n'; }
};
A globA(1);
B globB('a');
main()
{
int rc = 55;
A a(1001);
377
Transferring Control
try {
cout << "calling testeh\n";
testeh();
}
catch(char c) { cout << "caught char\n"; }
catch(short s) { cout << "caught short s = " << s << '\n'; }
catch(int i) { cout << "caught int i = " << i << '\n'; }
cout << "rc = " << rc << '\n';
return(rc);
testeh() throw(int,short)
{
A a(2001);
B b('k');
short k=12;
try {
cout << "testeh running\n";
throw (6);
}
catch(char c) { cout << "testeh caught char\n";}
catch(int j) { cout << "testeh caught int j = " << j << '\n';
try {
cout << "testeh throwing a short\n";
throw(k);
}
catch(char d) { cout << "char d caught\n"; }
}
cout << "this line should not be printed\n";
return(0);
Catching Exceptions
You can declare a handler to catch many types of exceptions. You declare the
allowable objects that a function can catch in the parentheses that follow 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 this handler can handle any exception that is thrown.
378
Transferring Control
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 that is caught must
have an accessible copy constructor. For more information on access, see Member
Access on page 299; on copy constructors, see Copy by Initialization on
page 332.
Order of Catching
Always place a catch block that catches a derived class before a catch block that
catches the base class of that derived class (that follows a try block). Consider 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. Then, 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.
func1();
try
{
func2();
}
catch (spec_err) { /* ... */ }
func3();
379
Transferring Control
}
catch (type_err) { /* ... */ }
// if no throw is issued, control resumes here.
If the above example throws spec_err within the inner try block (in this case, from
func2(), the inner catch block catches the exception. Assuming this catch block
does not transfer control, it calls func3(). If the example throws spec_err after the
inner try block (for instance, by func3()), the handler does not catch it, and OS/390
C/C++ calls the function terminate().
If the exception thrown from func2() in the inner try block is type_err, the program
skips out of both try blocks to the second catch block without invoking func3(). 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, OS/390 C/C++ calls unexpected(). The
function unexpected() is discussed in Special Exception Handling Functions on
page 386.
You can also nest a try block within a catch block.
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.
The handler has already caught the exception at the scope in which the rethrow
expression occurs. Consequently, the exception is rethrown to the next dynamically
enclosing try block. Therefore, catch blocks at the scope in which the rethrow
expression occurred cannot handle it. Any catch blocks following the dynamically
enclosing try block have an opportunity to catch the 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. The example then checks
for those exceptions it can handle. For any exception it cannot handle, it issues a
rethrow expression to rethrow the exception. This allows another handler in a
dynamically enclosing try block to handle the exception.
CBC3X16B
// This example illustrates rethrowing an exception.
#include <iostream.h>
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()
{
380
Transferring Control
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. When the example issues a
rethrow expression, it passes control out of the scope of the function f() into the
next dynamically enclosing block.
CBC3X16C
// This example illustrates a conditional expression
// used as a throw expression.
#include <iostream.h>
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 (...)
Chapter 17. C++ Exception Handling
381
Transferring Control
{
}
At first glance, it looks as if the block that catches integer values should do the
catch. However, the example converts i to a float value in the try block because it
is in a conditional expression with the float value f. Consider replacing the try block
in the example with the following try block:
try { throw doit ? i : j; }
382
CBC3X16D
// This example illustrates constructors and
// destructors in exception handling.
#include <string.h>
// needed for strcpy
#include <iostream.h>
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;
}
}
You can use exception handling in conjunction with constructors and destructors to
provide resource management. This resource management ensures that all locked
resources are unlocked when your program throws an exception.
class data
{
public:
void lock();
void unlock();
};
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. Use a helper class to write an exception-aware program for
resource management to correct this problem.
class data
{
public:
void lock();
void unlock();
};
class locked_data
//
//
//
//
// helper class
Chapter 17. C++ Exception Handling
383
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.
Exception Specifications
C++ provides a mechanism that limits a given function to throwing only a specified
list of exceptions. An exception specification at the beginning of any function acts as
a guarantee to the functions caller that the function will not directly or indirectly
throw any exception not contained in the exception specification. For example,
consider the following function:
void translate() throw(unknown_word,bad_grammar) { /* ... */ }
The above function 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(). Consider 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(). Then, OS/390 C/C++
calls unexpected(). The function unexpected() is discussed in Special Exception
Handling Functions on page 386.
There are qualifications to the rule about throwing only a specified list of exceptions.
If a class A is included in the exception specification of a function, the function will
also allow exception objects of any classes that are publicly derived from class A.
Also, if a pointer type B* is included in the exception specification of a function, the
function will allow exceptions of type B* or of pointers to any type publicly derived
from B*.
type
384
%&
Exception Specifications
,
%% return_type function_name ( '
) throw
argument
,
% (
'
type
) {
function_body }
%&
385
unexpected()
When a function with an exception specification throws an exception that is not
listed in its exception specification, the function void unexpected() is called. Next,
unexpected() calls a function specified by the set_unexpected() function. By
default, unexpected() calls the function terminate(). In turn, terminate() calls
abort by default, terminating the program.
Although unexpected() cannot return, it may throw an exception. The search for a
handler starts at the call of the function whose exception specification was violated.
For more information, see set_unexpected() and set_terminate().
terminate()
In some cases, the exception handling mechanism fails and a call to void
terminate() is made. This terminate() call occurs in any of the following
situations:
v When terminate() is explicitly called
v When no catch can be matched to a thrown object
v When the stack becomes corrupted during the exception-handling process
v 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.
A terminate function cannot return to its caller, either by using return or by throwing
an exception.
386
set_unexpected(old_unex);
try { f();}
catch(X)
{ /* ... */ }
catch(Y)
{ /* ... */ }
catch (...)
{ /* ... */ }
387
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.
388
Part 4. Appendixes
389
390
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 Initializing Arrays on page 102.
391
Character Constants
A character constant has type char in C++ and int in ANSI/ISO C.
For more information, see Character Constants on page 65.
For more information on typedef, see typedef on page 85. For information on
class types, see Chapter 11. C++ Classes on page 277. For information on
structures, see Structures on page 107.
For more information, see Scope of Class Names on page 282. For general
information about scope, see Scope in C++ on page 47.
Definitions
An object declaration is a definition in C++. In ANSI/ISO C, it is a tentative
definition. For example:
int i;
In C++, a global data object must be defined only once. In ANSI/ISO 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.
392
For more information, see Function Declarations on page 174 and Calling
Functions and Passing Arguments on page 184.
Enumerator Type
An enumerator has the same type as its enumeration in C++. In ANSI/ISO C, an
enumeration has type int.
For more information on enumerators, see Enumerations on page 91.
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/ISO C, an object of
enumeration type can be assigned values of any integral type.
For more information, see Enumerations on page 91.
Function Declarations
In C++, all declarations of a function must match the unique definition of a function.
ANSI/ISO C has no such restriction.
For more information, see Function Declarations on page 174.
In C++, this function declaration means that the function takes no arguments. In
ANSI/ISO C, it could take any number of arguments, of any type.
For more information, see Function Declarations on page 174.
Jump Statements
C++ does not allow you to jump over declarations containing initializations.
ANSI/ISO C does allow you to use jump statements for this purpose.
For more information, see Initializers on page 129.
393
Keywords
C++ contains some additional keywords not found in ANSI/ISO C. C programs that
use these keywords as identifiers are not valid C++ programs:
Table 13. C++ Keywords
asm
inline
catch
new
class
operator
delete
friend
protected
throw
public
template
this
private
try
virtual
wchar_t
main() Recursion
In C++, main() cannot be called recursively and cannot have its address taken.
ANSI/ISO C allows recursive calls and allows pointers to hold the address of
main().
For more information, see The main() Function on page 183.
Pointers to void
C++ allows void pointers to be assigned only to other void pointers. In ANSI/ISO 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 on page 100 and Pointers on page 95.
Prototype Declarations
C++ requires full prototype declarations. ANSI/ISO C allows nonprototyped
functions.
For more information, see Function Declarator on page 180.
__STDC__ Macro
The predefined macro variable __STDC__ is not defined for C++. It has the integer
value 0 when it is used a #if statement, indicating that the C++ language is not a
394
To avoid the error, place conditional compilation directives around the unsupported
pragma:
#ifndef __cplusplus
#
pragma runopts(stack(100K))
#endif
395
396
v Macros can be redefined without first being undefined (that is, without an
intervening #undef). An informational message is issued saying that the second
definition is used.
v The empty comment (/**/) in a function-like macro is equivalent to the ANSI/ISO
token concatenation operator ##.
The LANGLVL compiler option is described in the OS/390 C/C++ Users Guide.
#pragma langlvl is described in langlvl on page 254.
397
398
399
400
Implementation-Defined Behavior
The following sections describe how the OS/390 C compiler defines some of the
implementation-defined behavior from the ANSI/ISO C Standard.
v Identifiers
v Characters on page 402
v String Conversion on page 402
v Integers on page 403
v Floating-Point on page 403
v Arrays and Pointers on page 404
v Registers on page 404
v Structures, Unions, Enumerations, Bit Fields on page 404
v Declarators on page 405
v Statements on page 405
v Preprocessing Directives on page 405
v Library Functions on page 405
v Error Handling on page 406
v Signals on page 407
v Translation Limits on page 407
v Streams, Records, and Files on page 408
v Memory Management on page 409
v Environment on page 409
v Localization on page 410
v Time on page 410
Identifiers
The number of significant characters in an identifier with no external linkage:
v 1024
The number of significant characters in an identifier with external linkage:
v 1024 with the compile-time option LONGNAME specified
v 8 otherwise
The C++ compiler truncates external identifiers without C++ linkage after 8
characters if the NOLONGNAME compiler option or #pragma is in effect.
Case sensitivity of external identifiers:
v The linkage editor accepts all external names up to 8 characters, and may not be
case sensitive. The binder accepts all external names up to 1024 characters, and
is optionally case sensitive. The linkage editor accepts all external names up to 8
characters, and may not be case sensitive, depending on whether you use the
NOLONGNAME compiler option or #pragma. When using the OS/390 C compiler with
the NOLONGNAME option, all external names are truncated to 8 characters. As an
aid to portability, identifiers that differ only in case after truncation are flagged as
an error.
401
Implementation-Defined Behavior
Characters
Source and execution characters which are not specified by the ANSI/ISO standard:
v The caret (|) character in ASCII (bitwise exclusive OR symbol) or the equivalent
not () character in EBCDIC.
v The vertical broken line () character in ASCII which may be represented by the
vertical line (|) character on EBCDIC systems.
Shift states used for the encoding of multibyte characters:
v The shift states are indicated with the SHIFTOUT (hex value \x0E) characters and
SHIFTIN (hex value \x0F). Refer to the OS/390 C/C++ Run-Time Library
Reference for more information on wide character strings.
The number of bits that represent a character:
v 8 bits
The mapping of members of the source character set (characters and strings) to the
execution character set:
v The same code page is used for the source and execution character set.
The value of an integer character constant that contains a character/escape
sequence not represented in the basic execution character set:
v A warning is issued for an unknown character/escape sequence and the char is
assigned the character following the back slash.
The value of a wide character constant that contains a character/escape sequence
not represented in the extended execution character set:
v A warning is issued for the unknown character/escape sequence and the wchar_t
is assigned the wide character following the back slash.
The value of an integer character constant that contains more than one character:
v The lowest four bytes represent the character constant.
The value of a wide character constant that contains more than one multibyte
character:
v The lowest four bytes of the multibyte characters are converted to represent the
wide character constant.
Equivalent type of char: signed char, unsigned char, or user-defined:
v The default for char is unsigned
Is each sequence of white-space characters (excluding the new-line) retained or
replaced by one space character?
v Any spaces or comments in your source program will be interpreted as one
space.
String Conversion
Additional implementation-defined sequence forms that can be accepted by
strtod(), strtol() and strtoul() functions in other than the C locale:
v None
402
Implementation-Defined Behavior
Integers
Table 14. Integers
Type
Amount of
Storage
signed short
2 bytes
-32,768 to 32,767
unsigned short
2 bytes
0 to 65,535
signed int
4 bytes
unsigned int
4 bytes
0 to 4,294,967,295
signed long
4 bytes
unsigned long
4 bytes
0 to 4,294,967,295
8 bytes
-9,223,372,036,854,775,807 minus 1 to
9,223,372,036,854,775,807
8 bytes
0 to 18,446,744,073,709,551,615
Floating-Point
Table 15. Floating Point
Type
Amount of
Storage
Range (approximate)
IBM S/390 Hexadecimal
Format
float
4 bytes
5.5x10-79 to 7.2x1075
1.2x10-38 to 3.4x1038
double
8 bytes
5.5x10-79 to 7.2x1075
2.2x10-308 to 1.8x10308
long double
16 bytes
5.5x10-79 to 7.2x1075
3.4x10-4932 to 1.2x104932
The following is the direction of truncation (or rounding) when you convert an
integer number to an IBM S/390 hexadecimal floating-point number, or to an IEEE
binary floating-point number:
v IBM S/390 hexadecimal format:
Appendix D. Supporting ANSI/ISO Standards
403
Implementation-Defined Behavior
When the floating-point cannot exactly represent the original value, the value is
truncated.
When a floating-point number is converted to a narrower floating-point number,
the floating-point number is truncated.
v IEEE binary format:
The rounding direction is determined by the ROUND compiler option. The ROUND
option only affects the rounding of floating-point values that the OS/390 C/C++
compiler can evaluate at compile time. It has no effect on rounding at run time.
Registers
The effect of the register storage class specifier on the storage of objects in
registers:
v The register storage class indicates to the compiler that a variable in a block
scope data definition or a parameter declaration is heavily used (such as a loop
control variable). It is equivalent to auto, except that the compiler might, if
possible, place the variable into a machine register for faster access.
|
|
|
|
404
Implementation-Defined Behavior
The rule for bit fields crossing a storage unit boundary:
v Bit fields can cross storage unit boundaries.
The integral type that represents the values of an enumeration type:
v Enumerations can have the type char, short, or long and be either signed or
unsigned depending on their smallest and largest values.
Declarators
The maximum number of declarators (pointer, array, function) that can modify an
arithmetic, structure, or union type:
v The only constraint is the availability of system resources.
Statements
The maximum number of case values in a switch statement:
v Because the case values must be integers and cannot be duplicated, the limit is
INT_MAX.
Preprocessing Directives
Does the value of a single-character constant in a constant expression that controls
conditional inclusion match the value of the character constant in the execution
character set?
v Yes
Can such a constant have a negative value?
v Yes
The method of searching include source files (< >):
v See the OS/390 C/C++ Users Guide.
Is the search for quoted source file names supported (...)?
v User include files can be specified in double quotes. See the OS/390 C/C++
Users Guide.
The mapping between the name specified in the include directive and the external
source file name:
v See the OS/390 C/C++ Users Guide.
The behavior of each pragma directive:
v See Pragma Directives (#pragma) on page 238.
The definitions of __DATE__ and __TIME__ when date and time of translation is not
available:
v For OS/390 C/C++, the date and time of translation are always available.
Library Functions
The definition of NULL macro:
v NULL is defined to be a ((void *)0).
The format of diagnostic printed by the assert macro, and the termination behavior
(abort behavior):
v When assert is executed, if the expression is false, the diagnostic message
written by the assert macro has the format:
Assertion failed: expression, file filename, line line-number
405
Implementation-Defined Behavior
Set of characters tested by the isxxxx functions:
v To create a table of the characters set up by the ctype functions use the program
in the following example.
CBC3RABG
/* this example prints out ctest characters */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int ch;
for (ch = 0; ch <= 0xff; ch++)
{
printf("%#04X ", ch);
printf("%3s ", isalnum(ch)
printf("%2s ", isalpha(ch)
printf("%2s", iscntrl(ch)
printf("%2s", isdigit(ch)
printf("%2s", isgraph(ch)
printf("%2s", islower(ch)
printf("%c",
isprint(ch)
printf("%3s", ispunct(ch)
printf("%2s", isspace(ch)
printf("%3s", isprint(ch)
printf("%2s", isupper(ch)
printf("%2s", isxdigit(ch)
?
?
?
?
?
?
?
?
?
?
?
?
"AN"
"A"
"C"
"D"
"G"
"L"
ch
"PU"
"S"
"PR"
"U"
"X"
:
:
:
:
:
:
:
:
:
:
:
:
"
"
"
"
"
"
'
"
"
"
"
"
");
");
");
");
");
");
');
");
");
");
");
");
putchar('\n');
}
The result of calling fmod() function with the second argument zero (return zero,
domain error):
v fmod() returns a 0.
Error Handling
The format of the message generated by the perror() and strerror() functions:
v See the OS/390 Language Environment Debugging Guide and Run-Time
Messages for the messages emitted for perror() and strerror().
Note: errno is not emitted with the message.
How diagnostic messages are recognized:
v Refer to the OS/390 C/C++ Users Guide and the OS/390 Language Environment
Debugging Guide and Run-Time Messages for the lists of OS/390 C/C++
messages provided.
The different classes of messages:
v In general, messages are classified as shown by the following table.
406
Type of Message
Return Code
Information
00
Warning
10
Error
30
12
Severe error
> 30
16
Implementation-Defined Behavior
How the level of diagnostics can be controlled:
v Use the compile-time option FLAG to control the level of diagnostics. There is also
a compile-time option CHECKOUT which provides programming style diagnostics to
aid you in determining possible programming errors.
Signals
The set of signals for the signal() function:
v See the OS/390 C/C++ Users Guide.
The parameters and the usage of each signal recognized by the signal() function:
v See the OS/390 C/C++ Programming Guide.
The default handling and the handling at program start-up for each signal
recognized by signal() function:
v SIG_DFL is the default signal. See the OS/390 C/C++ Programming Guide for
more information on signal handling.
The signal blocking performed if the equivalent of signal(sig, SIG_DFL) is not
executed at the beginning of signal handler:
v See the OS/390 C/C++ Programming Guide.
Is the default handling reset if a SIGKILL is received by a signal handler?
v Whenever you enter the signal handler, SIG_DFL becomes the default.
Translation Limits
System-determined means that the limit is determined by your system resources.
Table 16. Translation Limits
Nesting levels of:
v Compound statements
v Iteration control
v Selection control
v Conditional inclusion
v Parenthesized declarators
v Parenthesized expression
Number of pointer, array and function declarators modifying an arithmetic a
structure, a union, and incomplete type declaration
v
v
v
v
v
v
v
System-determined
System-determined
System-determined
System-determined
System-determined
System-determined
System-determined
v
v
v
v
v
1024
1024
8
1024
1024
v
v
v
v
v
v
v
v
v
v
v
v
v
System-determined
System-determined
System-determined
System-determined
System-determined
System-determined
System-determined
32760 under MVS
32K minus 1
LONG_MAX (See 1)
SHRT_MAX
System-determined
System-determined
407
Implementation-Defined Behavior
Table 16. Translation Limits (continued)
Note:
1
LONG_MAX is the limit for automatic variables only. For all other variables,
the limit is 16 Megabytes.
408
Implementation-Defined Behavior
The input of %p conversion in the fscanf() function:
v The value is treated as an integer.
The interpretation of a - character that is neither the first nor the last in the scanlist
for %[ conversion in the fscanf() function:
v The sequence of characters on either side of the - are used as delimiters. For
example, %[a-f] will read in characters between 'a' and 'f'.
The value of errno on failure of fgetpos() and ftell() functions:
v This depends on the failure. For a list of the messages associated with errno,
see the OS/390 Language Environment Debugging Guide and Run-Time
Messages.
Memory Management
The behavior of calloc(), malloc() and realloc() functions if the size requested
is zero:
v Nothing is performed for calloc() and malloc(); realloc() frees the storage.
Environment
The arguments of main function:
v You can pass arguments to main through argv and argc.
What happens with open files when the abort() function is called?
v The files are closed.
What is returned to the host environment when the abort() function is called?
v The return code of 2000 is returned.
The form of successful termination when the exit function is called with argument
zero or EXIT_SUCCESS:
v All files are closed, all storage is released and the return code of 0 is returned.
The form of unsuccessful termination when the exit function is called with argument
EXIT_FAILURE:
v All files are closed, all storage is released and the return code of EXIT_FAILURE is
returned.
What status is returned by the exit function if the argument is other than zero,
EXIT_FAILURE and EXIT_SUCCESS?
v The return code 4096 is returned.
The set of environmental names:
v There are no environmental names.
The method of altering the environment list obtained by a call to the getenv()
function:
v See how to execute a command in the OS/390 C/C++ Run-Time Library
Reference.
The format and a mode of execution of a string on a call to the system() function:
v See the OS/390 C/C++ Run-Time Library Reference.
409
Implementation-Defined Behavior
Localization
The environment specified by the "" locale on a setlocale() call:
v EDC$SAAC
The supported locales:
v See the OS/390 C/C++ Programming Guide.
Time
The local time zone and Daylight Saving Time:
v This is specified in the locale.
The era for the clock() function:
v The era starts when the program is started by either a call from the operating
system, or a call to system(). Under TSO, the era starts when you log on to the
system. To measure the time spent in a program, call the clock() function at the
start of the program, and subtract its return value from the value returned by
subsequent calls to clock().
410
Notices
This information was developed for products and services offered in the U.S.A.
IBM may not offer the products, services, or features discussed in this document in
other countries. Consult your local IBM representative for information on the
products and services currently available in your area. Any reference to an IBM
product, program, or service is not intended to state or imply that only that IBM
product, program, or service may be used. Any functionally equivalent product,
program, or service that does not infringe any IBM intellectual property right may be
used instead. However, it is the users responsibility to evaluate and verify the
operation of any non-IBM product, program, or service.
IBM may have patents or pending patent applications covering subject matter
described 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:
IBM Director of Licensing
IBM Corporation
North Castle Drive
Armonk, NY 10504-1785
U.S.A.
For license inquiries regarding double-byte (DBCS) information, contact the IBM
Intellectual Property Department in your country or send inquiries, in writing, to:
IBM World Trade Asia Corporation
Licensing
2-31 Roppongi 3-chome, Minato-ku
Tokyo 106, Japan
The following paragraph does not apply to the United Kingdom or any other
country where such provisions are inconsistent with local law:
INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS
PUBLICATION AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OR CONDITIONS OF NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS
FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express
or implied warranties in certain transactions, therefore, this statement may not apply
to you.
This information could include technical inaccuracies or typographical errors.
Changes are periodically made to the information herein; these changes will be
incorporated in new editions of the publication. IBM may make improvements and/or
changes in the product(s) and/or the program(s) described in this publication at any
time without notice.
Any references in this information to non-IBM Web sites are provided for
convenience only and do not in any manner serve as an endorsement of those
Web sites. The materials at those Web sites are not part of the materials for this
IBM product and use of those Web sites is at your own risk.
IBM may use or distribute any of the information you supply in any way it believes
appropriate without incurring any obligation to you.
411
Licensees of this program who wish to have information about it for the purpose of
enabling: (i) the exchange of information between independently created programs
and other programs (including this one) and (ii) the mutual use of the information
which has been exchanged, should contact:
Lab Director
IBM Canada Ltd.
1150 Eglinton Avenue East
Toronto, Ontario M3C 1H7
Canada
Such information may be available, subject to appropriate terms and conditions,
including in some cases, payment of a fee.
The licensed program described in this information and all licensed material
available for it are provided by IBM under terms of the IBM Customer Agreement,
IBM International Program License Agreement, or any equivalent agreement
between us.
This information contains examples of data and reports used in daily business
operations. To illustrate them as completely as possible, the examples may include
the names of individuals, companies, brands, and products. All of these names are
fictitious and any similarity to the names and addresses used by an actual business
enterprise is entirely coincidental.
COPYRIGHT LICENSE:
This information contains sample application programs in source language, which
illustrates programming techniques on the OS/390 operating platforms. You may
copy, modify, and distribute these sample programs in any form without payment to
IBM, for the purposes of developing, using, marketing or distributing application
programs conforming to the application programming interface for the operating
platform for which the sample programs are written. These examples have not been
thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply
reliability, serviceability, or function of these programs. You may copy, modify, and
distribute these sample programs in any form without payment to IBM for the
purposes of developing, using, marketing, or distributing application programs
conforming to IBMs application programming interfaces.
If you are viewing this information softcopy, the photographs and color illustrations
may not appear.
Trademarks
The following terms are trademarks of International Business Machines Corporation
in the United States or other countries or both:
AD/Cycle
BookManager
C/370
DB2
DRDA
412
AIX
C Set ++
CICS
DB2 Universal Database
GDDM
AIX/6000
C++/MVS
CICS/ESA
DFSMS/MVS
Hiperspace
IBM
Language Environment
MVS/DFP
OpenEdition
OS/400
S/390
System/370
VisualAge
400
IMS
Library Reader
MVS/ESA
OS/2
QMF
SOM
System/390
VM/ESA
IMS/ESA
MVS
Open Class
OS/390
RACF
SP
System Object Model
VSE/ESA
Standards
Extracts are reprinted from IEEE Std 1003.11990, IEEE Standard Information
TechnologyPortable Operating System Interface (POSIX)Part 1: System
Application Program Interface (API) [C language], copyright 1990 by the Institute of
Electrical and Electronic Engineers, Inc.
Extracts are reprinted from IEEE P1003.1a Draft 6 July 1991, Draft Revision to
Information TechnologyPortable Operating System Interface (POSIX), Part 1:
System Application Program Interface (API) [C Language], copyright 1992 by the
Institute of Electrical and Electronic Engineers, Inc.
Extracts are reprinted from IEEE Std 1003.21992, IEEE Standard Information
TechnologyPortable Operating System Interface (POSIX)Part 2: Shells and
Utilities, copyright 1990 by the Institute of Electrical and Electronic Engineers, Inc.
Extracts are reprinted from IEEE Std P1003.4a/D61992, IEEE Draft Standard
Information TechnologyPortable Operating System Interface (POSIX)Part 1:
System Application Program Interface (API)Amendment 2: Threads Extension [C
language], copyright 1990 by the Institute of Electrical and Electronic Engineers,
Inc.
For more information on IEEE, visit their web site at http://www.ieee.org/.
Extracts from ISO/IEC 9899:1990 have been reproduced with the permission of the
International Organization for Standardization (ISO) and the International
Electrotechnical Commission (IEC). The complete standard can be obtained from
any ISO or IEC member or from the ISO or IEC Central Offices, Case postale 56,
CH - 1211 Geneva 20, Switzerland. Copyright remains ISO and IEC. For more
information on ISO, visit their web site at http://www.iso.ch/.
Extracts from X/Open Specification, Programming Languages, Issue 4 Release 2,
copyright 1988, 1989, February 1992, by the X/Open Company Limited, have been
Notices
413
414
Glossary
This glossary defines technical terms and
abbreviations that are used in OS/390 C/C++
documentation. If you do not find the term you are
looking for, refer to the index of the appropriate
OS/390 C/C++ manual or view IBM Dictionary of
Computing, located at:
http://www.ibm.com/networking/nsg/nsgmain.htm
A
|
|
|
|
|
|
|
|
415
|
|
|
|
416
|
|
|
|
417
C
C library. A system library that contains common C
language subroutines for file access, string operators,
character operations, memory allocation, and other
functions. IBM.
418
|
|
|
|
|
->
.*
->*
419
|
|
|
|
420
|
|
|
|
|
|
|
|
|
|
|
|
|
Glossary
421
422
D
data abstraction. A data type with a private
representation and a public set of operations (functions
or operators) which restrict access to that data type to
that set of operations. The C++ language uses the
concept of classes to implement data abstraction.
data definition (DD). (1) In the C and C++ languages,
a definition that describes a data object, reserves
storage for a data object, and can provide an initial
value for a data object. A data definition appears
outside a function or at the beginning of a block
statement. IBM. (2) A program statement that describes
the features of, specifies relationships of, or establishes
context of, data. ANSI/ISO. (3) A statement that is
stored in the environment and that externally identifies a
file and the attributes with which it should be opened.
data definition name. See ddname.
data definition statement. See DD statement.
data member. The smallest possible piece of
complete data. Elements are composed of data
members.
data object. (1) A storage area used to hold a value.
(2) Anything that exists in storage and on which
operations can be performed, such as files, programs,
classes, or arrays. (3) In a program, an element of data
structure, such as a file, array, or operand, that is
needed for the execution of a program and that is
named or otherwise specified by the allowable character
set of the language in which a program is coded. IBM.
data set. Under OS/390, a named collection of related
data records that is stored and retrieved by an assigned
name.
data stream. A continuous stream of data elements
being transmitted, or intended for transmission, in
character or binary-digit form, using a defined format.
IBM.
data structure. The internal data representation of an
implementation.
data type. The properties and internal representation
that characterize data.
Data Window Services (DWS). Services provided as
part of the Callable Services Library that allow
manipulation of data objects such as VSAM linear data
sets and temporary data objects known as
TEMPSPACE.
|
|
|
Glossary
423
|
|
|
|
|
|
|
424
|
|
|
|
|
425
426
|
|
|
|
|
F
feature test macro (FTM). A macro (#define) used to
determine whether a particular set of features will be
included from a header. X/Open. ISO.1.
FIFO special file. A type of file with the property that
data written to such a file is read on a first-in-first-out
basis. Other characteristics of FIFOs are described in
open(), read(), write(), and lseek(). X/Open. ISO.1.
file access permissions. The standard file access
control mechanism uses the file permission bits. The
bits are set at the time of file creation by functions such
as open(), creat(), mkdir(), and mkfifo() and can be
changed by chmod(). The bits are read by stat() or
fstat(). X/Open.
file descriptor. (1) A positive integer that the system
uses instead of the file name to identify an open file. (2)
A per-process unique, non-negative integer used to
identify an open file for the purpose of file access.
ISO.1.
The value of a file descriptor is from zero to
{OPEN_MAX}which is defined in <limits.h>. A process
can have no more than {OPEN_MAX} file descriptors
open simultaneously. File descriptors may also be used
to implement directory streams. X/Open.
file mode. An object containing the file mode bits and
file type of a file, as described in <sys/stat.h>. X/Open.
|
|
|
|
|
|
|
|
class me {
friend class you;
// ...
};
|
|
|
|
427
G
Generalization. Refers to a class, function, or static
data member which derives its definition from a
template. An instantiation of a template function would
be a generalization.
|
|
|
|
|
|
|
428
H
halfword. A contiguous sequence of bytes or
characters that constitutes half a computer word and
can be addressed as a unit. IBM.
hash function. A function that determines which
category, or bucket, to put an element in. A hash
function is needed when implementing a hash table.
hash table. (1) A data structure that divides all
elements into (preferably) equal-sized categories, or
buckets, to allow quick access to the elements. The
hash function determines which bucket an element
belongs in. (2) A table of information that is accessed by
way of a shortened search key (that hash value). Using
a hash table minimizes average search time.
header file. A text file that contains declarations used
by a group of functions, programs, or users.
heap storage. An area of storage used for allocation
of storage whose lifetime is not related to the execution
of the current routine. The heap consists of the initial
heap segment and zero or more increments.
hexadecimal constant. A constant, usually starting
with special characters, that contains only hexadecimal
digits. Three examples for the hexadecimal constant
with value 0 would be '\x00', '0x0', or '0X00'.
|
|
429
J
JCL (job control language). A control language used
to identify a job to an operating system and to describe
the job's requirement. IBM.
K
keyword. (1) A predefined word reserved for the C
and C++ languages, that may not be used as an
identifier. (2) A symbol that identifies a parameter in
JCL.
kind attribute. An attribute for a mutex attribute
object. This attribute's value determines whether the
mutex can be locked once or more than once for a
thread and whether state changes to the mutex will be
reported to the debug interface.
430
L
label. An identifier within or attached to a set of data
elements. ISO Draft.
Language Environment. Abbreviated form of OS/390
Language Environment. Pertaining to an IBM software
product that provides a common runtime environment
and runtime services to applications compiled by
Language Environment-conforming compilers.
last element. The element visited last in an iteration
over a collection. Each collection has its own definition
for last element. For example, the last element of a
sorted set is the element with the largest value.
late binding. Allowing the system to determine the
specific class of the object and invoke the appropriate
function implementations at run time. Late binding or
dynamic binding hides the differences between a group
of related classes from the application program.
leaves. Nodes without children. Synonymous with
terminals.
lexically. Relating to the left-to-right order of units.
library. (1) A collection of functions, calls, subroutines,
or other data. IBM. (2) A set of object modules that can
be specified in a link command.
linkage editor. Synonym for linker. The linkage editor
has been replaced by the binder for the MVS/ESA or
OS/390 operating systems. See binder.
Linkage. Refers to the binding between a reference
and a definition. A function has internal linkage if the
function is defined inline as part of the class, is declared
M
macro. An identifier followed by arguments (may be a
parenthesized list of arguments) that the preprocessor
replaces with the replacement code located in a
preprocessor #define directive.
macro call. Synonym for macro.
431
432
P
parameter. (1) In the C and C++ languages, an object
declared as part of a function declaration or definition
that acquires a value on entry to the function, or an
identifier following the macro name in a function-like
macro definition. X/Open. (2) Data passed between
programs or procedures. IBM.
parameter declaration. A description of a value that a
function receives. A parameter declaration determines
the storage class and the data type of the value.
parent enclave. The enclave that issues a call to
system services or language constructs to create a
nested or child enclave. See also child enclave and
nested enclave.
parent process. (1) The program that originates the
creation of other processes by means of spawn or exec
function calls. See also child process. (2) A process that
creates other processes.
parent process ID. (1) An attribute of a new process
identifying the parent of the process. The parent
process ID of a process is the process ID of its creator,
for the lifetime of the creator. After the creator's lifetime
has ended, the parent process ID is the process ID of
an implementation-dependent system process. X/Open.
(2) An attribute of a new process after it is created by a
currently active process. ISO.1.
partitioned concatenation. Specifying multiple PDSs
or PDSEs under one ddname. The concatenated data
sets act as one big PDS or PDSE and access can be
made to any member with a unique name. An attempted
access to a member whose name occurs more than
once in the concatenated data sets, returns the first
member with that name found in the entire
concatenation.
partitioned data set (PDS). A data set in direct
access storage that is divided into partitions, called
members, each of which can contain a program, part of
a program, or data. IBM.
partitioned data set extended (PDSE). Similar to
partitioned data set, but with extended capabilities.
path name. (1) A string that is used to identify a file. A
path name consists of, at most, {PATH_MAX} bytes,
including the terminating null character. It has an
Glossary
433
434
!
"
#
$
<percent-sign>
<ampersand>
<apostrophe>
<left-parenthesis>
<right-parenthesis>
<asterisk>
<plus-sign>
<comma>
<hyphen>
<hyphen-minus>
<period>
<slash>
<zero>
<one>
<two>
<three>
<four>
<five>
<six>
<seven>
<eight>
<nine>
<colon>
<semicolon>
<less-than-sign>
<equals-sign>
<greater-than-sign>
<question-mark>
<commercial-at>
%
&
'
(
)
*
+
,
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
@
<A>
<B>
<C>
<D>
<E>
<F>
<G>
<H>
<I>
<J>
<K>
<L>
<M>
<N>
<O>
<P>
<Q>
<R>
<S>
<T>
<U>
<V>
<W>
<X>
<Y>
<Z>
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
<left-square-bracket>
<backslash>
<reverse-solidus>
<right-square-bracket>
<circumflex>
<circumflex-accent>
<underscore>
<low-line>
<grave-accent>
<a>
<b>
[
\
\
]
|
|
_
_
v
a
b
<c>
<d>
<e>
<f>
<g>
<h>
<i>
<j>
<k>
<l>
c
d
e
f
g
h
i
j
k
l
<m>
<n>
<o>
<p>
<q>
<r>
<s>
<t>
<u>
<v>
<w>
<x>
<y>
<z>
m
n
o
p
q
r
s
t
u
v
w
x
y
z
<left-brace>
<left-curly-bracket>
<vertical-line>
<right-brace>
<right-curly-bracket>
<tilde>
{
{
|
}
}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 . _ -
Glossary
435
R
radix character. The character that separates the
integer part of a number from the fractional part.
X/Open.
real group ID. The attribute of a process that, at the
time of process creating, identifies the group of the user
who created the process. This value is subject to
change during the process lifetime, as describe in
setgid(). X/Open. ISO.1.
real user ID. The attribute of a process that, at the
time of process creation, identifies the user who created
the process. This value is subject to change during the
process lifetime, as described in setuid(). X/Open.
ISO.1.
reason code. A code that identifies the reason for a
detected error. IBM.
reassociation. An optimization technique that
rearranges the sequence of calculations in a subscript
expression producing more candidates for common
expression elimination.
redirection. In the shell, a method of associating files
with the input or output of commands. X/Open.
reentrant. The attribute of a program or routine that
allows the same copy of a program or routine to be
used concurrently by two or more tasks.
reference class. A class that links a concrete class to
an abstract class. Reference classes make
polymorphism possible with the Collection Classes.
Synonymous with indirection class.
436
437
438
T
tab character. A character that in the output stream
indicates that printing or displaying should start at the
next horizontal tabulation position on the current line.
The tab is the character designated by '\t' in the C
language. If the current position is at or past the last
defined horizontal tabulation position, the behavior is
unspecified. It is unspecified whether the character is
the exact sequence transmitted to an output device by
the system to accomplish the tabulation. X/Open.
This character is named <tab> in the portable character
set.
task library. A class library that provides the facilities
to write programs that are made up of tasks.
template. A family of classes or functions with variable
types.
template class. A class instance generated by a class
template.
Template Declaration. A prototype of a template
which can optionally include a template definition.
Template Definition. A blueprint the compiler uses to
generate a template instantiation.
template function. A function generated by a function
template.
Template Instantiation. Compiler generated code for
a class or function using the referenced types and the
corresponding class or function template definition.
terminals. Synonym for leaves.
text file. A file that contains characters organized into
one or more lines. The lines must not contain NUL
characters and none can exceed {LINE_MAX}which is
defined in limits.hbytes in length, including the
new-line character. The term text file does not prevent
the inclusion of control or other unprintable characters
(other than NUL). X/Open.
thread. The smallest unit of operation to be performed
within a process. IBM.
Glossary
439
U
ultimate consumer. The target of data in an I/O
operation. An ultimate consumer can be a file, a device,
or an array of bytes in memory.
ultimate producer. The source of data in an I/O
operation. An ultimate producer can be a file, a device,
or an array of byes in memory.
unary expression. An expression that contains one
operand. IBM.
undefined behavior. Action by the compiler and
library when the program uses erroneous constructs or
contains erroneous data. Permissible undefined
behavior includes ignoring the situation completely with
unpredictable results. It also includes behaving in a
documented manner that is characteristic of the
environment, during translation or program execution,
with or without issuing a diagnostic message. It can also
include terminating a translation or execution, while
issuing a diagnostic message. Contrast with unspecified
behavior and implementation-defined behavior.
440
V
value numbering. An optimization technique that
involves local constant propagation, local expression
elimination, and folding several instructions into a single
instruction.
variable. In programming languages, a language
object that may take different values, one at a time. The
values of a variable are usually restricted to a certain
data type. ISO-JTC1.
variant character. A character whose hexadecimal
value differs between different character sets. On
EBCDIC systems, such as S/390, these 13 characters
are an exception to the portability of the portable
character set.
<left-square-bracket>
<right-square-bracket>
<left-brace>
<right-brace>
<backslash>
<circumflex>
<tilde>
<exclamation-mark>
<number-sign>
<vertical-line>
<grave-accent>
<dollar-sign>
<commercial-at>
[
]
{
}
\
|
!
#
|
v
$
@
W
while statement. A looping statement that contains
the keyword while followed by an expression in
parentheses (the condition) and a statement (the
action). IBM.
white space. (1) Space characters, tab characters,
form-feed characters, and new-line characters. (2) A
sequence of one or more characters that belong to the
space character class as defined via the LC_CTYPE
category in the current locale. In the POSIX locale,
white space consists of one or more blank characters
(space and tab characters), new-line characters,
carriage-return characters, form-feed characters, and
vertical-tab characters. X/Open.
wide-character. A character whose range of values
can represent distinct codes for all members of the
largest extended character set specified among the
supporting locales.
wide-character code. An integral value corresponding
to a single graphic symbol or control code. X/Open.
wide-character string. A contiguous sequence of
wide-character codes terminated by and including the
first null wide-character code. X/Open.
wide-oriented stream. See orientation of a stream.
441
X
|
|
|
|
|
|
|
|
|
442
Bibliography
This bibliography lists the publications for IBM products that are related to the
OS/390 C/C++ product. It includes publications covering the application
programming task. The bibliography is not a comprehensive list of the publications
for these products, however, it should be adequate for most OS/390 C/C++ users.
Refer to OS/390 Information Roadmap, GC28-1727, for a complete list of
publications belonging to the OS/390 product.
Related publications not listed in this section can be found on the IBM Online
Library Omnibus Edition: MVS Collection CD-ROM (SK2T-0710), the IBM Online
Library Omnibus Edition: OS/390 Collection CD-ROM (SK2T-6700), or on a tape
available with OS/390.
|
OS/390
v OS/390 Introduction and Release Guide, GC28-1725
v OS/390 Planning for Installation, GC28-1726
v OS/390 Summary of Message Changes, GC28-1499
|
|
|
|
|
|
OS/390 C/C++
v OS/390 C/C++ Programming Guide, SC09-2362
v OS/390 C/C++ Users Guide, SC09-2361
|
|
|
|
|
v
v
v
v
v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OS/390
OS/390
OS/390
OS/390
OS/390
Assembler
v HLASM Language Reference, SC26-4940
v HLASM Programmers Guide, SC26-4941
443
COBOL
v
v
v
v
COBOL for OS/390 & VM Compiler and Run-Time Migration Guide, GC26-4764
Programming Guide, SC26-9049
Language Reference, SC26-9046
Diagnosis Guide, GC26-9047
PL/I
v PL/I for MVS & VM Language Reference, SC26-3114
v PL/I for MVS & VM Programming Guide, SC26-3113
v PL/I for MVS & VM Compiler and Run-Time Migration Guide, SC26-3118
VS FORTRAN
v Language and Library Reference, SC26-4221
v Programming Guide, SC26-4222
CICS
v CICS Application Programming Guide, SC34-5702
v CICS Application Programming Reference, SC34-5703
v CICS Distributed Transaction Programming Guide, SC34-5708
v CICS Front End Programming Interface Users Guide, SC34-5710
v CICS Messages and Codes, GC33-5716
v CICS Resource Definition Guide, SC34-5722
v
v
v
v
v
v
CICS
CICS
CICS
CICS
CICS
CICS
DB2
v DB2 Administration Guide, SC26-8957
v DB2 Application Programming and SQL Guide, SC26-8958
v DB2 Call Level Interface Guide and Reference, SC26-8959
v DB2 Command Reference, SC26-8960
v
v
v
v
v
DB2
DB2
DB2
DB2
DB2
444
IMS/ESA
v
v
v
v
IMS/ESA Application
IMS/ESA Application
IMS/ESA Application
IMS/ESA Application
SC26-8726
v
v
v
v
Programming:
Programming:
Programming:
Programming:
QMF
DFSMS
v OS/390 DFSMS Introduction, SC26-7344
v OS/390 DFSMS: Managing Catalogs, SC26-7338
v
v
v
v
OS/390
OS/390
OS/390
OS/390
Bibliography
445
446
INDEX
Special Characters
[ ] array subscript operators 141
decrement operator 143
? : conditional operators 161
/= compound assignment operator 164
*= compound assignment operator 164
&= compound assignment operator 164
+= compound assignment operator 164
\ continuation character 67, 216
== equal to operator 156
\ escape character 68
++ increment operator 143
&& logical AND operator 159
!= not equal to operator 156
?? trigraphs 54
+ addition operator 154
& address operator 145
__ANSI__ macro 226
__BFP__ macro 227
& bitwise AND operator 157
__cdecl 125
__CHARSET_LIB__ macro 227
, comma operator 165
/ division operator 153
double quotation mark 66
__EXTENDED__ macro 227
* indirection operator 145
! logical negation operator 144
* multiplication operator 153
# preprocessor directive character 216
# preprocessor operator 221
= simple assignment operator 163
bitwise negation operator 144
| (caret), locale 54
|= compound assignment operator 164
| bitwise exclusive OR operator 158
_Export keyword 127
>= greater than or equal to operator 155
>>= compound assignment operator 164
>> right-shift operator 154
> greater than operator 155
<= less than or equal to operator 155
<<= compound assignment operator 164
<< left-shift operator 154
< less than operator 155
_LONG_LONG macro 229
| (vertical bar), locale 54
Numerics
370 macro
232
A
abort function 386
abstract classes 355
access
base classes 342
constructors 317
declarations 287, 343
derived class 341
effective 346
exception handling 379
friends 304
inherited member 341
members 299
multiple 349
private 342
protected members 342
public 342
resolution 345
specifiers 300, 340, 342
summary example 347
virtual function 354
accessibility 299, 345, 349
additive operators
addition + 154
subtraction 154
address operator & 145
aggregate classes
constructors and destructors 317
description 278
aggregate operands 135
ALIAS compile option 259
aliasing, type-based 136
alignment rules
changing with #pragma pack 266
nested structures 114
structures 114
unions 119
allocation expressions 148
ambiguities
base classes 348, 350
conversions 169
resolving 202
virtual functions 353
AND operator (bitwise) & 157
AND operator (logical) && 159
anonymous
unions 118
unions in C 117
ANSI, implementation-defined behavior
ANSI aliasing 136
ANSI flagging 254
ANSI/ISO standards 401
ANSI macro 226
argc (argument count)
argument to main 183
in different environments 41
argument count 183
argument vector 183
arguments
best-matching 307
command line 36
401
447
arguments (continued)
const 308
default 189, 318
default initializers in templates
in a function call 184
matching 306
matching conversions 307
pass by reference 188
passing 41
template
matching 365, 368
nontype 363
type 360
to main function 36, 183
trivial conversions 308, 365
virtual functions 352
volatile 308
argv (argument vector)
argument to main 183
in different environments 41
restriction 41
arithmetic
conversions 170
operands 135
arrays
ANSI/ISO support 404
class members 288
declaring 101
operands 135
subscripting operators 141
overloading 313
arrow operator 142
ASCII character codes 69
assignment
memberwise 313
operators
copying classes 331
default for classes 331
overloading 312
assignment expression
compound 164
description 163
simple 163
associativity of operators 133
auto storage class specifier 75
358
B
base classes
abstract 355
access 341, 342
ambiguities 348, 350
description 338
direct 337, 347
indirect 337, 348
initialization 327, 329
multiple 347
multiple access 349
pointers to 340, 345, 352
virtual 348, 351
base list 338, 340, 348
448
158
C
C and C++ differences 391
call, function 184
call scope 345
carriage return escape sequence \r 68
case label 210
cast
argument-matching conversions 307
expressions 146
cast (continued)
function style 320
catch
argument matching 379
exceptions 378
keyword 374
no match 386
char constant 65
char type specifier 87
character
constants 65
data types 87
escape sequence 68
set 53
string constant 66
chars pragma 243
CHARSET_LIB macro 227
checkout pragma 243
class key 278
class member access operators
argument-matching conversions 307
description 142
overloading 314
class member lists 287
class members 287
class names
description 279
scope 282
class object 74
class operands 135
class scope 48
class templates
declarations 362
definitions 362
description 361
friends 370
instantiation 361
member functions 369
static members 371
classes 335, 337
abstract 355
aggregate 278, 317
class
templates 360
class templates 360
class-type members 288
constructors 317
conversions 325
copying
by assignment 331
by initialization 332
restrictions 331
declarations 278
derivation 338
destructors 317
friends 301
incomplete declarations 282, 288, 338
inheritance 335
initialization 327
local 284
member access 299
449
D
data
abstraction 43
hiding 44
data members
description 288
scope 291
static 297
DATE macro 225
dbx 23
deallocation expression 151
debug tool 19
debugging
dbx 23
debug tool 19
decimal constant 63
decimal data type operators 148
450
declarations
access 343
class
description 278
incomplete 282, 288, 338
member 287
syntax 278
templates 362
description 71
file scope 72, 73
friend 301, 304
function 174
matching 305
resolving ambiguities 202
templates 367
in source files 34
matching 305
parameter 181
pointers to members 292
resolving ambiguous statements
template functions 367
declarators
array 101
character 87
description 121
floating-point 88
integer 91
member 287
pointer 95
restrictions 405
union 116
decrement operator 314
decrement operator () 143
default
arguments 317, 318
assignment operator 331
clause 210, 211
constructors 318, 329
copy constructors 332
initializers in templates 358
label 211
member access 301
define pragma 247
define preprocessor directive 217
defined unary operator 234
definitions
class templates 362
function templates 367
in source files 34
macro 217
member function 289
template classes 362
template functions 367
delete operator
description 151
free store 322
overloading 316
dereferencing operator 145
derived classes
access 341
access declarations 343
202
E
EBCDIC character codes 69
effective access 346
elaborated type specifier 282
elif preprocessor directive 234
ellipsis
argument-matching conversions
function call operator 313
in overloaded operator 311
type checking 181
user-defined conversions 307
else clause 207
else preprocessor directive 236
empty argument list 181
encapsulation 44
end of string 66
endif preprocessor directive 236
enum 91
enumeration
ANSI/ISO support 404
307
enumeration (continued)
enum data types 91
enumeration constant 92
operands 135
enumerator 92
environment
implementation-defined behavior
pragma 248
equal to operator == 156
equality operators
equal to == 156
not equal to != 156
error messages 238
error preprocessor directive 223
errors
ANSI/ISO support 406
message classes 406
escape character \ 68
escape sequence 68, 402
evaluation, expression 133
examples
cbc3raa 199
cbc3raa1 197
cbc3raa2 198
cbc3raa3 200
cbc3raa4 200
cbc3raa6 206
cbc3raa7 214
cbc3raa8 220
cbc3raa9 220
cbc3raaa 34
cbc3raab 35
cbc3raaf 76
cbc3raag 76
cbc3raai 82
cbc3raak 85
cbc3raam 100
cbc3raan 94
cbc3raao 105
cbc3raap 106
cbc3raaq 99
cbc3raas 113
cbc3raat 179
cbc3raau 182
cbc3raav 176
cbc3raaw 176
cbc3raax 187
cbc3raay 187
cbc3rabc 236
cbc3rabd 238
cbc3rabe 252
cbc3rabg 406
cbc3rabi 213
cbc3rah1 81
cbc3rah2 81
cbc3rah3 81
cbc3raj1 84
cbc3raj2 84
cbc3rmax 36
cbc3x02d 47
cbc3x02f 49
409
INDEX
451
examples (continued)
cbc3x02g 49
cbc3x02h 49
cbc3x02i 50
cbc3x02j 51
cbc3x02k 68
cbc3x02l 69
cbc3x06a 188
cbc3x06b 189
cbc3x06c 141
cbc3x07e 201
cbc3x08a 232
cbc3x08b 232
cbc3x08c 232
cbc3x10a 300
cbc3x10b 280
cbc3x10c 278
cbc3x10d 278
cbc3x10e 282
cbc3x11a 291
cbc3x11b 293
cbc3x11c 294
cbc3x11d 294
cbc3x11e 296
cbc3x11f 297
cbc3x11g 298
cbc3x11h 299
cbc3x11i 302
cbc3x11j 302
cbc3x12a 305
cbc3x12b 309
cbc3x12c 310
cbc3x12d 315
cbc3x12e 315
cbc3x13a 328
cbc3x14a 339
cbc3x14b 339
cbc3x14c 340
cbc3x14d 344
cbc3x14e 345
cbc3x14f 347
cbc3x14g 350
cbc3x15a 358
cbc3x15b 368
cbc3x16a 376
cbc3x16b 380
cbc3x16c 381
cbc3x16d 383
cbc3x16f 377
machine-readable 9
naming of 9
softcopy 9
exception handling
access 379
catching exceptions 378
constructors 382
destructors 382
exception specifications
empty 385
unexpected 385
order of catching 379
452
F
FETCHABLE preprocessor directive
field, bit 110
file inclusion 224
FILE macro 226
file scope
description 73
257
408
functions (continued)
friend 301
inline 194
main 36, 183
operator delete() 322
operator new() 322
overloading 305
overview 173
parameter 184
pointers to 192
polymorphic 338
prototypes 178
return statements 208
return values 191
specifiers 131, 194
template 365
virtual 289, 338, 351, 353
void 176
G
global variables 77
goto statement 206
greater than operator > 155
greater than or equal to operator >=
155
H
handler list 374
hdrstop pragma 249
hexadecimal constant 63
hexadecimal numbers as escape sequences
HHW370 macro 228
hidden
names 138, 280, 282
virtual functions 352
HOSMVS macro 228
68
I
IBMC macro 228
IBMCPP macro 228
identifiers
ANSI/ISO support 401
description 58
external names in OS/390 C/C++ 60
limits in names 61
linkage of 38
if preprocessor directive 234
if statement 207
ifdef preprocessor directive 235
ifndef preprocessor directive 235
IGNERRNO macro 228
implementation-defined behavior 401
implementation dependency
allocation of floating-point types 88
allocation of integral types 90
bit field length 111
class member allocation 288
order of argument passing 185
sign of char 87
INDEX
453
454
integer
ANSI/ISO support 403
conversions 168
data types 90
floating-point constant 63
integer constants 62
integral
operands 135
promotions 167, 307
internal linkage 39
isolated_call pragma 253
K
keywords
__cdecl 125
_Export 127
description 59
L
label statement 195
langlvl pragma 254
leaves pragma for function calls 256
left-shift operator << 154
less than operator < 155
less than or equal to operator <= 155
library functions 405
LIBREL macro 229
limits
floating-point 403
integer 403
line continuation
escape sequence, as an 68
preprocessor directives, in 216
string constants, in 67
LINE macro 226
line preprocessor directive 237
linkage of identifiers 38
linkage pragma for interlanguage calls 256
linkage specifications 50
linking to non-C++ programs 50
literal 66
local
classes 284
scope 37, 47
type names 285
variables 37, 72
LOCALE macro 229
localization 410
logical AND operator && 159
logical negation operator ! 144
logical OR operator || 160
long double type specifier 88
long long
conversions 168
type specifier 90
long name support 61
long type specifier 90
LONGNAME compiler option 61
LONGNAME macro 229
longname pragma
loop statements
do 201
for 203
while 214
lvalue 136
258
M
macro
definition 217, 218
invocation 218
main function
description 183
parameters to 36
program execution 36
map pragma 259
margins pragma 261
matching arguments
description 306
exception handling 379
template functions 365, 368
member functions
constant 289
constructors 317
definition 289
description 289
destructors 317
inline 290
local classes 284
overloading operators 310
special 290, 317
static 299
templates 369
this pointer 293, 354
volatile 289
member lists 279, 287
member of a structure 108
members
access
default 301
inherited 341
public, private, and protected 300
arrays 288
class member access operators 142
class type 288
data 288
declaration 287
declarator 287
inherited 338
initialization 327, 329
initializer list 317
of classes 287
overloading class access operators 314
pointers to 160, 292
protected 342
scope 291
static 283, 295
virtual functions 289
memberwise assignment 313
memory
data mapping 131
management 409
MI_BUILTIN
macro 229
minus, unary operator 144
modifying access 343
modulo operator % 153
multibyte characters
ANSI/ISO support 402
overview 402
multiple
access 349
inheritance 336, 347
multiplicative operators
division / 153
multiplication * 153
remainder % 153
MVS (Multiple Virtual System)
macro 230
variable names 60
N
name spaces 40
names
class 279, 282
dominant 340
hidden 138, 280, 282
local type 285
types 385
naming
classes 40
external names 60
long names 60
negation operators
bitwise 144
logical ! 144
nested classes
access declarations 344
friend scope 304
scope 283
nested template arguments 361
nested try blocks 379
nested visibility 37
nesting level limits 407
new-line character
escape sequence \n 68
white space, as 216
new operator
description 148
free store 322
overloading 316
noinline pragma 251, 262
NOLONGNAME compiler option 61
nolongname pragma 258
nomargins pragma 261
nosequence pragma 270
not equal to operator != 156
Notices 411
null character \0 66
INDEX
455
216
O
object-like macro 217
objects
base class 348
class
copying 331
declarations 280
initialization 327
construction order 319
of class objects 319
of derived classes 330
constructors 318
conversion to 325
data abstraction 43
description 74
destruction order 321
destructors 318
explicitly constructing 320
temporary 192, 318, 321, 324
octal constant 63
octal numbers as escape sequences
ones complement operator 144
operator 221
operator delete() function 322
operator new() function 322
operators 221
.* (pointer-to-member) 160
:: (scope resolution) 138
. (dot) 142
->* (pointer-to-member) 160
-> (arrow) 142
additive
addition operator + 154
subtraction 154
assignment
compound 164
copying classes 331
default 331
description 163
overloading 312
simple = 163
associativity 133
binary 152, 311
bitwise AND & 157
bitwise exclusive OR | 158
bitwise inclusive OR | 158
bitwise shift
left-shift << 154
right-shift >> 154
comma 165
conditional ? : 161
delete
description 151
free store 322
456
68
264
options (continued)
specifying 263
pragma 263
run-time 268
OR operator (logical) || 160
order
of catching exceptions 379
template declaration 362, 367
OS linkage 257
output operator 49
overloading
functions
access declarations 345
argument matching 306
arguments 307
declaration matching 305
restrictions 306
operators
argument matching 306
assignment 312
class member access 314
decrement 314
delete 316, 322, 324
description 308
function call 313
general rules 309
increment 314
member functions 310
new 316, 322
operands 310
restrictions 311
subscript 313
resolution for template functions 365
special operators 312
overriding virtual functions 352, 354
P
pack pragma 266
packed
assignments and comparisons 164
structures 112, 185
unions 116, 185
Packed qualifier 124
page pragma 267
pagesize pragma 267
parameter declaration list 181
parameter passing 184
parameters, to main function 36
parentheses
for calling functions 140
for grouping expressions 138
passing a value 186
passing an address 186
passing an argument by reference 188
phases of preprocessing 216
PL/I linkage 257
placement syntax 149, 322
plus, unary operator 144
pointer-to-member
conversions 169
pointer-to-member (continued)
declarations 292
operators 160
pointers
arrays 404
conversions 168
description 95
this 293
to functions 192
to members 160, 292
polymorphism 44, 338, 340
portability issues 401
POSIX 399
pound sign (#)
preprocessor directive character 216
preprocessor operator 221
pragma definitions
define 247
implementation 250
info 250
noinline 262
priority 267
pragma directives
csect 246
exporting functions and variables 248
leaves 256
linkage 256
reachable 268
runopts 268
variable 273
wsizeof 273
pragmas
chars 243
checkout 243
comment 244
convlit 245
csect 246
define 247
disjoint 247
environment 248
filetag 249
hdrstop 249
implementation 250
info 250
inline 251
IPA considerations 242
isolated_call 253
langlvl 254
leaves 256
linkage 256
longname 258
map 259
margins 261
noinline 251, 262
nolongname 258
nomargins 261
nosequence 270
option_override 264
options 263
pack 266
page 267
INDEX
457
pragmas (continued)
pagesize 267
priority 267
reachable 268
runopts 268
sequence 270
skip 271
strings 271
subtitle 271
target 272
title 273
variable 273
wsizeof 273
precedence of operators 133
precisionof operator 148
predefined macros
_LONG_LONG 229
370 232
ANSI 226
BFP 227
CHARSET_LIB 227
CODESET 227
COMMONC 227
COMPAT 227
COMPILER_VER 227
DATE 225
DIGRAPHS 227
DLL 227
EXTENDED 227
FILE 226
FILETAG 228
FUNCTION 228
HHW370 228
HOSMVS 228
IBMC 228
IBMCPP 228
IGNERRNO 228
INITAUTO 228
INITAUTO_W 229
LIBREL 229
LINE 226
LOCALE 229
LONGNAME 229
MI_BUILTIN 229
MVS 230
SAA 230
SAAL2 230
STDC 226
STRING_CODE_SET 230
TARGET_LIB 230
TEMPINC 231
THW370 231
TIME 226
TIMESTAMP 231
TOSMVS 231
XPLINK 232
preprocessing, phases of 216
preprocessor directive character
preprocessor directives
## operator 222
# operator 221
458
Q
qualified
class name 138
type name 283
qualifiers
_Packed 124
const 122
volatile 122
216
S
SAA macro 230
SAAL2 macro 230
scalar operands 135
scope
block 37
call 345
class names 282
description 37, 47
file 37
friend 303
function 37
local classes 284
member 291
nested classes 283
reference 345
scope resolution operator
ambiguous base classes 350
class member access 346
description 138
inheritance 339
virtual functions 353
sequence pragma 270
set_new_handler() library function 150
set_terminate() library function 386
set_unexpected() library function 386
shift operators (<< and >>) 154
shift states 402
short type specifier 90
signal
function 407
handler 375
signed char type specifier 87
signed int 90
signed long 90
signed long long 90
simple assignment operator = 163
simple I/O 48
single inheritance 335
sizeof operator 146
skip pragma 271
source
files 35
source (continued)
program 34
margins 261
variable names 60
space character 216
special functions
member functions 290, 317
used in exception handling 386
specifications
exception 384
linkage 50
specifiers
access 300, 340, 342
base 340
class 278
declaration 287
inline 131, 194
pure 288, 289
virtual 131
splice preprocessor directive ## 222
standard conversions 167
statements
ANSI/ISO support 405
block 196
break 197
continue 199
do 201
expression 202
for 203
goto 206
if 207
labels 195
null 208
overview 195
resolving ambiguities 202
return 191, 208
switch 210
while 214
static
binding 44, 338
data members 297
initialization of data members 298
member functions 299
members 283, 295
storage class specifier 83
STDC macro 226
storage class specifiers
auto 75
extern 77
register 83
static 83
storage duration 40
storage of variables 131
streams 408
string
constants 66
conversion 402
literals 66
STRING_CODE_SET macro 230
strings pragma 271
struct type specifier 108
INDEX
459
structures
ANSI/ISO support 404
packing
using _Packed qualifier 112
using #pragma pack 266
subdeclarator 122
subscript declarator
description 122
in arrays 101
subscript operator
overloading 313
subscripts 141
subtitle pragma 271
subtraction operator 154
supporting ANSI/ISO 401
switch statement 210
syntax diagrams, how to read 10
T
tab character
horizontal escape sequence \t 68
vertical escape sequence \v 68
white space, as 216
TARGET_LIB macro 230
target pragma 272
TEMPINC macro 231
template classes
declaration 362
definition 362
description 361
explicit definition 364, 372
instantiation 371
template functions
declarations 367
definitions 367
description 365
explicit definition 366
grouping definitions of 366
instantiation 368
overloading resolution 365
templates
#pragma define 247
#pragma implementation 250
argument
list 358, 360
nested list 361
nontype 363
class templates 360
constructors 362, 370
declaration 357
default initializers 358
friends 370
function templates 365
identifier 358
member functions 369
pragma define 247
pragma implementation 250
static data members 371
syntax 357
temporary objects 192, 318, 321, 324
460
385
U
unary expression 142
unary minus operator 144
unary operators
address operator (&) 145
bitwise negation operator 144
decrement operator () 143
increment operator ++ 143
indirection operator * 145
logical negation operator ! 144
minus 144
overloading 311
plus 144
sizeof operator 146
unary plus operator (+) 144
undef preprocessor directive 221
underscores in identifiers 60
unexpected() library function 384
unexpected function 386
union specifier 115
unions
anonymous in C 117
anonymous in C++ 118
ANSI/ISO support 404
constructors and destructors 317
member destructors 320
packing
using _Packed qualifier 116
using #pragma pack 266
unsigned char type specifier 87
unsigned int type specifier 90
unsigned long long type specifier 90
unsigned long type specifier 90
unsigned short type specifier 90
unsigned type specifier 90
user-defined
conversions 307, 325
types 277
306
variables (continued)
block scope data declarations 72
character 87
enumeration 91
file scope data declarations 73
floating-point 88
integer 90
local 37
names 60
pointer 95
storage of 131
structure 107
union 114
virtual
base classes 348, 351
destructors 317
function specifier 131
functions
access 354
ambiguous calls to 353
description 351
dynamic binding 338
hidden 352
overriding 352, 354
pure 355
keyword 340
member functions 289
visibility
block 37, 48
class members 299
description 37
nested 37
void 100
void function 176
volatile
keyword 308
member functions 289
qualifier 122
W
wchar_t 66
while statement 214
white space 56, 215, 216, 221
wide character constant 66
wide characters
ANSI/ISO support 402
wsizeof pragma 273
X
XPLINK macro
232
V
variable arguments 181
variable pragma 273
variables
array 101
INDEX
461
462
SC09-2360-05