The first time the compiler encounters the file, the name COORDIN_H_ should be undefined. (I chose a name based on the include filename, with a few underscore characters tossed in to create a name that is unlikely to be defined elsewhere.) That being the case, the compiler looks at the material between the #ifndef and the #endif, which is what you want. In the process of looking at the material, the compiler reads the line defining COORDIN_H_. If it then encounters a second inclusion of coordin.h in the same file, the compiler notes that COORDIN_H_ is defined and skips to the line following the #endif. Note that this method doesn’t keep the compiler from including a file twice. Instead, it makes the compiler ignore the contents of all but the first inclusion. Most of the standard C and C++ header files use this guarding scheme. Otherwise you might get the same structure defined twice in one file, and that will produce a compile error.
Listing 9.2. file1.cpp
// file1.cpp -- example of a three-file program
#include
#include "coordin.h" // structure templates, function prototypes
using namespace std;
int main()
{
rect rplace;
polar pplace;
cout << "Enter the x and y values: ";
while (cin >> rplace.x >> rplace.y) // slick use of cin
{
pplace = rect_to_polar(rplace);
show_polar(pplace);
cout << "Next two numbers (q to quit): ";
}
cout << "Bye!\n";
return 0;
}
Listing 9.3. file2.cpp
// file2.cpp -- contains functions called in file1.cpp
#include
#include
#include "coordin.h" // structure templates, function prototypes
// convert rectangular to polar coordinates
polar rect_to_polar(rect xypos)
{
using namespace std;
polar answer;
answer.distance =
sqrt( xypos.x * xypos.x + xypos.y * xypos.y);
answer.angle = atan2(xypos.y, xypos.x);
return answer; // returns a polar structure
}
// show polar coordinates, converting angle to degrees
void show_polar (polar dapos)
{
using namespace std;
const double Rad_to_deg = 57.29577951;
cout << "distance = " << dapos.distance;
cout << ", angle = " << dapos.angle * Rad_to_deg;
cout << " degrees\n";
}
Compiling and linking these two source code files along with the new header file produces an executable program. Here is a sample run:
Enter the x and y values: 120 80
distance = 144.222, angle = 33.6901 degrees
Next two numbers (q to quit): 120 50
distance = 130, angle = 22.6199 degrees
Next two numbers (q to quit): q
By the way, although we’ve discussed separate compilation in terms of files, the C++ Standard uses the term
Multiple Library Linking
The C++ Standard allows each compiler designer the latitude to implement name decoration or mangling (see the sidebar “What Is Name Decoration?” in Chapter 8, “Adventures in Functions”) as it sees fit, so you should be aware that binary modules (object-code files) created with different compilers will, most likely, not link properly. That is, the two compilers will generate different decorated names for the same function. This name difference will prevent the linker from matching the function call generated by one compiler with the function definition generated by a second compiler. When attempting to link compiled modules, you should make sure that each object file or library was generated with the same compiler. If you are provided with the source code, you can usually resolve link errors by recompiling the source with your compiler.
Storage Duration, Scope, and Linkage
Now that you’ve seen a multifile program, it’s a good time to extend the discussion of memory schemes in Chapter 4, “Compound Types,” because storage categories affect how information can be shared across files. It might have been a while since you last read Chapter 4, so let’s review what it says about memory. C++ uses three separate schemes (four under C++11) for storing data, and the schemes differ in how long they preserve data in memory:
• Automatic storage duration— Variables declared inside a function definition—including function parameters—have automatic storage duration. They are created when program execution enters the function or block in which they are defined, and the memory used for them is freed when execution leaves the function or block. C++ has two kinds of automatic storage duration variables.
• Static storage duration— Variables defined outside a function definition or else by using the keyword static have static storage duration. They persist for the entire time a program is running. C++ has three kinds of static storage duration variables.