B. Stroustrup - The C++ Programming Language (794319), страница 91
Текст из файла (страница 91)
Thiscan be done by providing a using-declaration for each declaration in <cstdio>:// stdio.h:#include<cstdio>using std::printf;// ...Section 14.4.9C Headers417Another advantage is that the using-declaration for printf() prevents a user from (accidentally ordeliberately) defining a nonstandard printf() in the global scope.
I consider nonlocal using-directives primarily a transition tool. I also use them for essential foundation libraries, such as the ISOC++ standard library (std). Most code referring to names from other namespaces can be expressedmore clearly with explicit qualification and using-declarations.The relationship between namespaces and linkage is described in §15.2.5.14.5 Advice[1][2][3]Use namespaces to express logical structure; §14.3.1.Place every nonlocal name, except main(), in some namespace; §14.3.1.Design a namespace so that you can conveniently use it without accidentally gaining accessto unrelated namespaces; §14.3.3.[4] Avoid very short names for namespaces; §14.4.2.[5] If necessary, use namespace aliases to abbreviate long namespace names; §14.4.2.[6] Avoid placing heavy notational burdens on users of your namespaces; §14.2.2, §14.2.3.[7] Use separate namespaces for interfaces and implementations; §14.3.3.[8] Use the Namespace::member notation when defining namespace members; §14.4.[9] Use inline namespaces to support versioning; §14.4.6.[10] Use using-directives for transition, for foundational libraries (such as std), or within a localscope; §14.4.9.[11] Don’t put a using-directive in a header file; §14.2.3.This page intentionally left blank15Source Files and ProgramsForm must follow function.– Le Corbusier•••••Separate CompilationLinkageFile-Local Names; Header Files; The One-Definition Rule; Standard-Library Headers; Linkage to Non-C++ Code; Linkage and Pointers to FunctionsUsing Header FilesSingle-Header Organization; Multiple-Header Organization; Include GuardsProgramsInitialization of Nonlocal Variables; Initialization and Concurrency; Program TerminationAdvice15.1 Separate CompilationAny realistic program consists of many logically separate components (e.g., namespaces; Chapter14).
To better manage these components, we can represent the program as a set of (source code)files where each file contains one or more logical components. Our task is to devise a physicalstructure (set of files) for the program that represents the logical components in a consistent, comprehensible, and flexible manner. In particular, we aim for a clean separation of interfaces (e.g.,function declarations) and implementations (e.g., function definitions).
A file is the traditional unitof storage (in a file system) and the traditional unit of compilation. There are systems that do notstore, compile, and present C++ programs to the programmer as sets of files. However, the discussion here will concentrate on systems that employ the traditional use of files.Having a complete program in one file is usually impossible. In particular, the code for thestandard libraries and the operating system is typically not supplied in source form as part of a420Source Files and ProgramsChapter 15user’s program. For realistically sized applications, even having all of the user’s own code in a single file is both impractical and inconvenient. The way a program is organized into files can helpemphasize its logical structure, help a human reader understand the program, and help the compilerenforce that logical structure.
Where the unit of compilation is a file, all of the file must be recompiled whenever a change (however small) has been made to it or to something on which it depends.For even a moderately sized program, the amount of time spent recompiling can be significantlyreduced by partitioning the program into files of suitable size.A user presents a source file to the compiler. The file is then preprocessed; that is, macro processing (§12.6) is done and #include directives bring in headers (§2.4.1, §15.2.2). The result of preprocessing is called a translation unit. This unit is what the compiler proper works on and what theC++ language rules describe.
In this book, I differentiate between source file and translation unitonly where necessary to distinguish what the programmer sees from what the compiler considers.To enable separate compilation, the programmer must supply declarations providing the typeinformation needed to analyze a translation unit in isolation from the rest of the program. The declarations in a program consisting of many separately compiled parts must be consistent in exactlythe same way the declarations in a program consisting of a single source file must be. Your systemhas tools to help ensure this.
In particular, the linker can detect many kinds of inconsistencies. Thelinker is the program that binds together the separately compiled parts. A linker is sometimes (confusingly) called a loader. Linking can be done completely before a program starts to run. Alternatively, new code can be added to the running program (‘‘dynamically linked’’) later.The organization of a program into source files is commonly called the physical structure of aprogram. The physical separation of a program into separate files should be guided by the logicalstructure of the program. The same dependency concerns that guide the composition of programsout of namespaces guide its composition into source files. However, the logical and physical structures of a program need not be identical.
For example, it can be helpful to use several source filesto store the functions from a single namespace, to store a collection of namespace definitions in asingle file, or to scatter the definition of a namespace over several files (§14.3.3).Here, we will first consider some technicalities relating to linking and then discuss two ways ofbreaking the desk calculator (§10.2, §14.3.1) into files.15.2 LinkageNames of functions, classes, templates, variables, namespaces, enumerations, and enumeratorsmust be used consistently across all translation units unless they are explicitly specified to be local.It is the programmer’s task to ensure that every namespace, class, function, etc., is properlydeclared in every translation unit in which it appears and that all declarations referring to the sameentity are consistent.
For example, consider two files:// file1.cpp:int x = 1;int f() { /* do something */ }Section 15.2Linkage421// file2.cpp:extern int x;int f();void g() { x = f(); }The x and f() used by g() in file2.cpp are the ones defined in file1.cpp. The keyword extern indicatesthat the declaration of x in file2.cpp is (just) a declaration and not a definition (§6.3). Had x beeninitialized, extern would simply be ignored because a declaration with an initializer is always a definition.
An object must be defined exactly once in a program. It may be declared many times, butthe types must agree exactly. For example:// file1.cpp:int x = 1;int b = 1;extern int c;// file2.cpp:int x;extern double b;extern int c;// means ‘‘int x = 0;’’There are three errors here: x is defined twice, b is declared twice with different types, and c isdeclared twice but not defined. These kinds of errors (linkage errors) cannot be detected by a compiler that looks at only one file at a time. Many, however, are detectable by the linker. For example, all implementations I know of correctly diagnose the double definition of x.
However, theinconsistent declarations of b are uncaught on popular implementations, and the missing definitionof c is typically only caught if c is used.Note that a variable defined without an initializer in the global or a namespace scope is initialized by default (§6.3.5.1). This is not the case for non-static local variables or objects created onthe free store (§11.2).Outside a class body, an entity must be declared before it is used (§6.3.4).
For example:// file1.cpp:int g() { return f()+7; }int f() { return x; }int x;// error : f() not (yet) declared// error : x not (yet) declaredA name that can be used in translation units different from the one in which it was defined is said tohave external linkage. All the names in the previous examples have external linkage. A name thatcan be referred to only in the translation unit in which it is defined is said to have internal linkage.For example:static int x1 = 1;const char x2 = 'a';// internal linkage: not accessible from other translation units// internal linkage: not accessible from other translation unitsWhen used in namespace scope (including the global scope; §14.2.1), the keyword static (somewhat illogically) means ‘‘not accessible from other source files’’ (i.e., internal linkage).
If youwanted x1 to be accessible from other source files (‘‘have external linkage’’), you should removethe static. The keyword const implies default internal linkage, so if you wanted x2 to have externallinkage, you need to precede its definitions with extern:422Source Files and Programsint x1 = 1;extern const char x2 = 'a';Chapter 15// external linkage: accessible from other translation units// external linkage: accessible from other translation unitsNames that a linker does not see, such as the names of local variables, are said to have no linkage.An inline function (§12.1.3, §16.2.8) must be defined identically in every translation unit inwhich it is used (§15.2.3).
Consequently, the following example isn’t just bad taste; it is illegal:// file1.cpp:inline int f(int i) { return i; }// file2.cpp:inline int f(int i) { return i+1; }Unfortunately, this error is hard for an implementation to catch, and the following – otherwise perfectly logical – combination of external linkage and inlining is banned to make life simpler forcompiler writers:// file1.cpp:extern inline int g(int i);int h(int i) { return g(i); } // error : g() undefined in this translation unit// file2.cpp:extern inline int g(int i) { return i+1; }// ...We keep inline function definitions consistent by using header files(§15.2.2). For example:// h.h:inline int next(int i) { return i+1; }// file1.cpp:#include "h.h"int h(int i) { return next(i); }// fine// file2.cpp:#include "h.h"// ...By default, const objects (§7.5), constexpr objects (§10.4), type aliases (§6.5), and anythingdeclared static (§6.3.4) in a namespace scope have internal linkage.
Consequently, this example islegal (although potentially confusing):// file1.cpp:using T = int;const int x = 7;constexpr T c2 = x+1;// file2.cpp:using T = double;const int x = 8;constexpr T c2 = x+9;Section 15.2Linkage423To ensure consistency, place aliases, consts, constexprs, and inlines in header files (§15.2.2).A const can be given external linkage by an explicit declaration:// file1.cpp:extern const int a = 77;// file2.cpp:extern const int a;void g(){cout << a << '\n';}Here, g() will print 77.The techniques for managing template definitions are described in §23.7.15.2.1 File-Local NamesGlobal variables are in general best avoided because they cause maintenance problems.