Listing 13.2. An example of shadowing with an extern variable
1 #include <stdio.h>
2
3 unsigned i = 1;
4
5 int main(void) {
6 unsigned i = 2; /* A new object */
7 if (i) {
8 extern unsigned i; /* An existing object */
9 printf("%u\n", i);
10 } else {
11 printf("%u\n", i);
12 }
13 }
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":1},{\"line\":0,\"ch\":2}],[{\"line\":2,\"ch\":18},{\"line\":2,\"ch\":19}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":1}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":1}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":1}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":1}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":13}],[{\"line\":1,\"ch\":1},{\"line\":1,\"ch\":2}],[{\"line\":5,\"ch\":20},{\"line\":5,\"ch\":21}],[{\"line\":11,\"ch\":1},{\"line\":11,\"ch\":2}],[{\"line\":2,\"ch\":1},{\"line\":2,\"ch\":2}],[{\"line\":12,\"ch\":1},{\"line\":12,\"ch\":2}],[{\"line\":2,\"ch\":5},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":15}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":24}],[{\"line\":3,\"ch\":1},{\"line\":3,\"ch\":2}],[{\"line\":4,\"ch\":1},{\"line\":4,\"ch\":2}],[{\"line\":4,\"ch\":5},{\"line\":4,\"ch\":8}],[{\"line\":8,\"ch\":11},{\"line\":8,\"ch\":14}],[{\"line\":10,\"ch\":11},{\"line\":10,\"ch\":14}],[{\"line\":4,\"ch\":9},{\"line\":4,\"ch\":13}],[{\"line\":4,\"ch\":14},{\"line\":4,\"ch\":18}],[{\"line\":5,\"ch\":1},{\"line\":5,\"ch\":2}],[{\"line\":2,\"ch\":5},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":15}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":24}],[{\"line\":6,\"ch\":1},{\"line\":6,\"ch\":2}],[{\"line\":6,\"ch\":7},{\"line\":6,\"ch\":9}],[{\"line\":7,\"ch\":1},{\"line\":7,\"ch\":2}],[{\"line\":7,\"ch\":9},{\"line\":7,\"ch\":24}],[{\"line\":8,\"ch\":1},{\"line\":8,\"ch\":2}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":10,\"ch\":9},{\"line\":10,\"ch\":15}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":2}],[{\"line\":9,\"ch\":9},{\"line\":9,\"ch\":13}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":2}],[{\"line\":8,\"ch\":9},{\"line\":8,\"ch\":15}],[{\"line\":10,\"ch\":9},{\"line\":10,\"ch\":15}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":2}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":2}]]"}
!@%STYLE%@!
Trace the two objects named `i`: the local object is 2, so execution enters the `if` block. There, `extern unsigned i` refers to the file-scope object, whose value is 1. The program prints 1. section 13.2
The name visible at a point in a program does not, by itself, tell you how long its object exists. Storage duration concerns an object's storage; scope concerns where an identifier is visible. A declaration can refer to an existing object, while a definition creates a distinct one. section 13.2
The distinctions matter when choosing how to create and initialize an object:
- Static storage lasts for the whole execution. An `extern` declaration can designate a static-duration object defined at file scope, including in another translation unit. section 13.2
- A local variable in a recursive function has a separate storage instance for each call. Do not mistake repeated use of its name for reuse of one instance. section 13.0
- Dynamic allocation creates storage that must be tracked and freed. Allocated storage, like automatic storage, needs explicit initialization; static and thread-storage-duration objects receive default initialization. section 13.0 section 13.4
TAKEAWAY: Visibility and usability are different. A nested declaration may shadow a local name without making the earlier object unusable: a pointer obtained before the shadowing can still be passed to a function that changes that object. section 13.2
Table 13.1. Storage classes, scope, linkage of identifiers, and storage duration of the associated objects Tentative indicates that a definition is implied only if there is no other definition with an initializer. Induced indicates that the linkage is internal if another declaration with internal linkage has been met prior to that declaration; otherwise, it is external. (view table figure)
Use the table to compare a declaration's storage class, scope, linkage, storage duration, and lifetime rather than treating those properties as interchangeable. section 13.2
Initialization is a practical consequence of the duration distinction. Static and thread-storage-duration objects default to zero-initialized members. For automatic or allocated objects, establish a well-defined state explicitly; for allocated data, a type-specific initialization function can keep allocation and initialization together. section 13.4

