Linking the Dots #4: Linkage in C
Overview: The $3$ Types of C Linkage (Only $1$ Actually Links)
这里我们参考 IBM: XL C/C++ for AIX - Program linkage, 但需要 tailor 一下去掉 C++ 的部分。
- External linkage: identifiers can be referred to from any other translation units in the entire program
- Internal linkage: identifiers can be referred to from all scopes in the current translation unit
- No linkage: identifiers can be referred to only from the scope it is in
What is a Translation Unit (TU)?
wikipedia: Translation unit (programming):
a translation unit (or more casually a compilation unit) is the ultimate input to a C or C++ compiler from which an object file is generated.
What is external linkage and internal linkage?:
a source file from your implementation plus all the headers you
#included in it.
External Linkage
In global scope, identifiers for the following kinds of entities declared without the
staticstorage class specifier have external linkage:
- An object
- A function
这里强调 file/global scope,与前文 Linking the Dots #3: C Scopes > 与 linking/linkage 的关系 是一致的。
[!caution] “object” in $C$ context
variable, pointer, member of an array, member of a struct, memory allocated via
malloc这些都算是 $C$ 的 object, 它的严格定义是:An object is a region of data storage in the execution environment, the contents of which can represent values.
在我们讨论 linkage 的范围内,这里这个 “an object” 其实就只有 variable 这么一种情况。有时候 document 写得太保守、太怕出错了,就会搞得很难理解。
Internal Linkage
The following kinds of identifiers have internal linkage:
- Objects or Functions explicitly declared with the
staticstorage class specifier at file/global scope.- Identifiers that were previously declared with internal linkage (e.g., a second declaration of the same
staticvariable).
[!caution] WTF
internal linkage 的 variable 或者 function 并不要 linker 来 resolve; compiler 自己就能搞定,毕竟在一个 translation unit 内部。
Then why on earth did you decide to call it “linkage”?
No Linkage
The following kinds of identifiers have no linkage:
- Local Objects:
declared inside a block that is not explicitly marked with theexternkeyword.
- This includes
autoandregistervariables.- Function Parameters (which are local to that function body)
- Labels used for
gototargets are restricted to the function where they are defined.- Type Definitions and Metadata: this includes
typedefnames,enumenumerators, andstruct/uniondeclared within a local scope.
[!caution]
externhas NOTHING to do with linkage真的非常讨厌把
extern纳入 linkage 的讨论。简单一点的话,可以认为 local object defined, instead of declared, inside a block have no linkage.
你
extern是 forward declaration, 这个 variable 的 linkage 要看它真正的定义。比如:void process_data(void) { // 你这个 extern 和 answer 的实际 linkage 没有半毛钱关系 // 你只是在 **要求** answer 是 external linkage,否则 link 不上 extern int answer; // ... use answer ... int whatever = 3; // internal linkage }
因为 type 是 no linkage,所以如果要 import 一个 type,一般的做法有两种:
- 把 type 的 definition 放到 header
secondary.h中,然后main.c去#include "secondary.h",做成一个 translation unit, 让它实际变成 internal linkage - 或者用 The “Pointer Trick” (PIMPL: Pointer to IMPLementation)
You cannot use a name with no linkage to declare an entity with linkage. For example, you cannot use the name of a structure or enumeration or a
typedefname referring to an entity with no linkage to declare an entity with linkage.The following example demonstrates this:
- the compiler will not allow the declaration of
a1with external linkage — structureAhas no linkage.- the compiler will not allow the declaration of
a2with external linkage — thetypedefnamemyAhas no linkage becauseAhas no linkage.int main() { struct A { }; // extern A a1; // compile error typedef A myA; // extern myA a2; // compile error }
留下评论