Knowing how to use technical documentation is an important skill for any computer professional. For programmers, this skill includes knowing how to translate language-specific library function descriptions into correct programming statements. C++ documentation comes in various formats from a variety of vendors and organizations. Although C++ documentation varies from one source to the next, their many similarities lessen the challenge of going between them.
Regardless of the source, the most common feature, always located at or very near the top of the document, is a list of one or more function prototypes. Your task as a programmer is to convert these prototypes into working function calls. Recall from an earlier section that prototypes include typing information (the return and parameter types), but typing information is not included in function calls. Furthermore, programmers choose the corresponding argument names based on the underlying programming problem and are not required to use the names appearing in the documentation. C++ documentation typically includes other sections that are not consistently labeled or ordered.
Section Header | |||||
---|---|---|---|---|---|
| cplusplus.com1 | Microsoft Developer Network2 | Unix/Linux man pages | ||
Function Name | function | Unlabeled3 | NAME | ||
Prototype | Follows function name3 | Syntax | SYNOPSIS | ||
Header File | Follows function name3 | Requirements | SYNOPSIS | ||
Brief Description | Derived from function4 | Unlabeled3 | DESCRIPTION | ||
Input | Parameters | Parameters | SPECIAL VALUES5 | ||
Return Value | Return Value | Output | N/A6 |
||
Example | Example | Example | N/A7 |
||
Related Documentation | See also | See Also | SEE ALSO |
C++ inherits the C runtime library (CRT) from the C programming language. It is a set of procedural-paradigm functions supporting various semi-primitive operations - common to many problem domains but too high-level for direct language implementation. The CRT consists of functions (with few global variables), and given the ubiquity of their prototypes in the language documentation, the current chapter is the ideal place to begin our discussion of using documentation to write programs. The following discussion is appropriate for the kind of data covered previously, but we'll return to documentation in Chapter 8 as part of our coverage of strings. We begin with error reporting and type aliases.
The problems global variables cause notwithstanding, many CRT library functions use one nevertheless: errno (short for error number). For example, the sqrt function's domain is all non-negative numbers - passing it a negative number is an illegal operation. The function does not "crash" when called with a negative argument but returns a value representing Not a Number (NaN), and the program continues, propagating the NaN through the subsequent computations. If this error occurs near the beginning of a long, time-consuming calculation, the computer wastes the time between the erroneous call and the end of the calculation. Worse still, if a human doesn't immediately view the results, the error might not be detected until much later.
CRT functions assign a value to errno before returning, so a program must check the value immediately after returning from a function, before calling another, to avoid overwriting the previous value. Functions encode different error conditions with various integer values: zero indicates success, while a non-zero value indicates an error. Several symbolic constants represent specific errors: for example, EDOM (domain error) or ERANGE (range error).
#include <iostream> #include <cmath> using namespace std; int main() { double x = sqrt(-2); if (errno != 0) cout << errno << ": " << x << endl; else cout << x << endl; return 0; } |
33: -nan(ind) |
(b) | |
perror("sqrt error"); | |
(c) | |
sqrt error: Domain error | |
(d) | |
(a) |
Type aliases have some of the same benefits as symbolic constants, creating shorter, more meaningful type names. For example, unsigned long
is shortened to size_t
. While the new type name is only slightly shorter, it conveys additional meaning to someone reading a program: the variable definition size_t i;
informs the reader that the program uses the variable to store the size of a program entity. Similarly, the alias errno_t
1 creates a data type appropriate for holding error numbers as described above. Type aliases always improve a program's readability and sometimes make it more portable.
C and C++ are deliberately vague about the size and sign of some specific data types. For example, the size of an int can vary from 2 to 8 bytes (16- to 64-bits), with the exact size chosen to match the word size of the hardware. This ambiguity can sometimes make choosing the best data type for a particular task difficult. One solution is to create "dummy" placeholder data types. The compiler replaces the placeholder names with "real" data types through a typedef expansion: typedef unsigned long size_t;
.
Standard portable data type names usually end with _t, and the full name suggests how programs use the type. Programmers typically put the type alias definitions in header files - with the function prototypes when they are tied to specific functions or the standard header file <sys/types.h> when they are more general.
If the function parameters are all simple, fundamental data types (like the pow and sqrt functions), converting the function prototype into a working function call is relatively easy, becoming increasingly easier with practice. However, converting a prototype into working code can become more challenging when the parameters are more complex objects (i.e., instances of structures or classes). The frequent use of default arguments and overloaded functions may also confuse new C++ programmers. The time and effort spent understanding argument passing and related concepts pay substantial dividends here. The following examples demonstrate both simple and more complex library functions and how to convert the prototypes in the documentation into working code.
The pow function demonstrates how programmers convert the documentation's prototype and other descriptions into working C++ code.
Documentation Prototype | Program Function Call |
---|---|
double pow(double base, double exponent); double pow(double x, double y); |
cout << pow(3.14159, 2.0) << endl; double result = pow(h, 2); double payment = p * r / (1 - pow(1 + r, -n)); |
(a) | (b) |
Although Linux no longer provides the ftime function, the text uses it to demonstrate a "real world" use of a structure passed-by-pointer and other documentation features, including a confusing problem programmers encounter when first learning to convert documentation into programs. ftime gets the time, measured in seconds and milliseconds, since "the world began" or, more formally, since the epic. For Unix, Linux, and macOS, the epic is January 1, 1970; for Windows, it is January 1, 1980. The function gets the elapsed time from the computer hardware via the operating system, so it represents a special kind of function called a system call. System calls are often unique to a given operating system, and even when two systems support the same call, the function and argument names may differ, as the next figure illustrates.
Windows | Unix/Linux/macOS |
---|---|
#include <sys/timeb.h>
errno_t _ftime_s(struct _timeb *timeptr);
|
#include <sys/timeb.h>
int ftime(struct timeb *tp);
|
(a) | (b) |
Windows | Unix/Linux/macOS |
---|---|
struct _timeb* start; // error!!
_ftime_s(start); |
struct timeb* start; // error!!
ftime(start); |
struct _timeb start; // correct
_ftime_s(&start); |
struct timeb start; // correct
ftime(&start); |