owned this note
owned this note
Published
Linked with GitHub
# C99 - 6. Language
## 6.2 Concepts
### [6.2.1 Scopes of identifiers](http://port70.net/~nsz/c/c99/n1256.html#6.2.1)
[1](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p1) An **identifier**
can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program.
> **identifier** [識別碼/標識符](https://zh.wikipedia.org/wiki/%E6%A8%99%E8%AD%98%E7%AC%A6)
[2](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p2) For each different entity that an identifier designates, ==the identifier is **visible** (i.e., can be used) only within a region of program text== called its scope. ++Different entities designated by the same identifier++ *either* have different scopes, *or* are in different name spaces. There are four kinds of scopes: `function`, `file`, [`block`](https://hackmd.io/yP9-qHGTRMOwyTNYBgaHzg?both#3-A-block), and `function prototype`. (A function prototype is a declaration of a function that declares the types of its parameters.)
> 延伸閱讀: § **Scope** in chapter 2 *OBJECTS, FUNCTIONS, AND TYPES* in ⟨EFFECTIVE C⟩
>
> Objects, functions, macros, and other C language identifiers have *scope* that ==delimits the contiguous region where they can be accessed==.
](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p3) & [4](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p4) & § **Scope** in chapter 2 *OBJECTS, FUNCTIONS, AND TYPES* in ⟨EFFECTIVE C⟩
- for the four scopes, if the declaration appears
- *file scope*: outside any block or parameter list
- *block scope*: inside a block or within the list of parameters
:notes: *block*: [§ 6.8 Statement and blocks ¶3](https://hackmd.io/yP9-qHGTRMOwyTNYBgaHzg?view#3-A-block)
It's usually bounded by a `\{\}` pair.
**An example**:
The identifiers for `a` and `b` from [Listing 2-4]() have block scope and can be used to refer to only these variables within the code block in the main function in which they’re defined.
```c
#include <stdio.h>
void swap(int *pa, int *pb) { // pa → a: 21 pb → b: 17
int t = *pa; // t: 21
*pa = *pb; // pa → a: 17 pb → b: 17
*pb = t; // pa → a: 17 pb → b: 21
}
int main(void) {
int a = 21; // a: 21
int b = 17; // b: 17
swap(&a, &b);
printf("a = %d, b = %d\n", a, b); // a: 17 b: 21
return 0;
}
```
- *function prototype scope*: within the list of parameter declarations in a function prototype (not part of a function definition)
- which terminates at the end of the function declarator
--> the area between "{ }"
- *function scope*: A `label` name is the only kind of identifier that has function scope.
*Labels* are identifiers ++followed by a colon++ and ==identify a statement in a ++function++ to which control may be transferred==. Chapter 5 covers labels and control transfer.
- [x] Study **Chapter 5** for more detail on labels: [The goto Statement](https://hackmd.io/MhVEcOc9QZS-9owoS6lGJA?view#The-goto-Statement)
- In [4](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p4), also mentions that: *If an identifier designates two different entities in the same name space, the scopes might overlap.*
If so, the scope of one entity (the inner scope) will be a strict subset of the scope of the other entity (the outer scope).
the entity declared in the outer scope ==is hidden (and not visible)== within the inner scope.
> In ⟨EFFECTIVE C⟩,
> Scopes can be nested, with inner and outer scopes.
> :star: As the name implies, any inner scope must be completely contained
>
> Solution: The easiest way to prevent this from becoming a problem is to use different names.
> Using short names such as i and j is fine for identifiers with small scopes.
>
> Listing 2-5 demonstrates different scopes
```c
int j; // file scope of j begins
void f(int i) { // block scope of i begins
int j = 1; // block scope of j begins; hides file-scope j
i++; // i refers to the function parameter
for (int i = 0; i < 2; i++) { // block scope of loop-local i begins
int j = 2; // block scope of the inner j begin; hides outer j
printf("%d\n", j); // inner j is in scope, prints 2
} // block scope of the inner i and j ends
printf("%d\n", j); // the outer j is in scope, prints 1
} // the block scope of i and j ends
void g(int j); // j has function prototype scope; hides file-scope j
```
*Listing 2-5: Scope*
- [ ] (To-be-studied) [5-7]()
### 6.2.2 Linkages of identifiers
Origin
- `External`
- From the **K&R C**: [Definiton of external variable](https://hackmd.io/HL6odhjYTTqKxOHjkW327A#Definiton-of-external-variable)
Because external variables are globally accessible, they can be used instead of argument lists to communicate data between functions.
> 函式間的資料的分享或交換,透過外部變數可以取代參數列,函式內可以直接存取該變數。
Definition and rules
> Refs.:
> [6.2.2 Linkages of identifiers](http://port70.net/~nsz/c/c99/n1256.html#6.2.2) in C99[^first]
> Linkage section on chapter 10 PROGRAM STRUCTURE in Effective C[^second]
> [1.10 External Variable and Scope in K&R C](https://hackmd.io/HL6odhjYTTqKxOHjkW327A?view#110-External-Variable-and-Scope)
- Quick note
- on C99
[visible](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p2)
[block scope](http://port70.net/~nsz/c/c99/n1256.html#6.8p3)
[block](http://port70.net/~nsz/c/c99/n1256.html#6.8p3)
> A block allows a set of declarations and statements to be grouped into one syntactic unit
> :notes: syntactic unit: between left brace and the matching right brace (ref. 4.8 Block Structure in K&R C)
#### [1](http://port70.net/~nsz/c/c99/n1256.html#6.2.2p1) An [identifier](https://hackmd.io/yP9-qHGTRMOwyTNYBgaHzg?view#621-Scopes-of-identifiers) *declared* ==in different scopes or in the same scope more than once== can be made to ++refer to the same object or function by a process++ called linkage.[**21)**](http://port70.net/~nsz/c/c99/n1256.html#note21)
There are three kinds of linkage: external, internal, and none.
> [From **Effective C**] Linkage is a process that ==controls whether an interface is public or private== and ==determines whether any two identifiers refer to the same entity==.
>
> 延伸閱讀:Scope: [6.2.1 Scopes of identifiers on C99](https://hackmd.io/MVSNZhEaQr2GXSwyom-odg?view#621-Scopes-of-identifiers)
[2](http://port70.net/~nsz/c/c99/n1256.html#6.2.2p2) In the set of [translation units](https://hackmd.io/CZzsLgQ0R1eb_FLD0FHTng?view#Definition) and libraries that constitutes an entire program each declaration of a particular identifier with
- external linkage
denotes ==the same object or function==
- internal linkage
++Within one translation unit++, each declaration of an identifier with internal linkage denotes ==the same object or function==.
- no linkage
denotes ==a unique entity==
> **Examples** from ⟨EFFECTIVE C⟩
> Listing 10-1 shows examples of declarations of each kind of linkage.[^second]
```c
static int i; // i is declared with explicit internal linkage.
extern void foo(int j) {
// foo is declared with explicit external linkage.
// j has no linkage because it is a parameter.
}
```
#### [3](http://port70.net/~nsz/c/c99/n1256.html#6.2.2p3) If the declaration of *a file scope identifier* for ++an object++ or ++a function++ contains *the storage-class specifier* **static**, ==the identifier has internal linkage==.[**22)**](http://port70.net/~nsz/c/c99/n1256.html#note22)
> For `storage-class specifier`:
> - reference the [note](https://hackmd.io/MVSNZhEaQr2GXSwyom-odg?both#624-Storage-durations-of-objects) on the next chapter 6.2.4 in C99
> - also [**Storage Duration**](https://hackmd.io/MhVEcOc9QZS-9owoS6lGJA#Storage-Duration) introduced in ⟨EFFECTIVE C⟩
[4](http://port70.net/~nsz/c/c99/n1256.html#6.2.2p4) For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,[**23)**](http://port70.net/~nsz/c/c99/n1256.html#note23)
### [6.2.4 Storage durations of objects](http://port70.net/~nsz/c/c99/n1256.html#6.2.4)
#### [1](http://port70.net/~nsz/c/c99/n1256.html#6.2.4p1) An object has a storage duration that determines its lifetime.
#### [2](http://port70.net/~nsz/c/c99/n1256.html#6.2.4p2) The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it.
An object exists, has a constant address,[**25)**](http://port70.net/~nsz/c/c99/n1256.html#note25) and retains its last-stored value throughout its lifetime.[**26)**](http://port70.net/~nsz/c/c99/n1256.html#note26)
If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime.
### [6.2.5 Types](http://port70.net/~nsz/c/c99/n1256.html#6.2.5)
#### [1](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p1)
==The meaning of a value stored in an object or returned by a function is determined by the type of the expression used to access it.== (An identifier declared to be an object is the simplest such expression; the type is specified in the declaration of the identifier.)
Types are partitioned into object types (types that fully describe objects), function types (types that describe functions), and **incomplete types** (types that describe objects but lack information needed to determine their sizes).
- An example of `incomplete types`:
[19](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p19) The `void` type comprises an empty set of values; it is an *incomplete type* that cannot be completed.
[2](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p2)
An object declared as type ==\_Bool== is large enough to store the values 0 and 1.
[25](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p25)
A type is characterized by its type category, which is either the outermost derivation of a derived type (as noted above in the construction of derived types), or the type itself if the type consists of no derived types.
[26](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p26)
Any type so far mentioned is an unqualified type. Each unqualified type has several qualified versions of its type,[**38)**](http://port70.net/~nsz/c/c99/n1256.html#note38) corresponding to the combinations of one, two, or all three of the const, volatile, and restrict qualifiers(CV修飾字).
> - The `restirct` is one of `qualifier`, to make an unqualified type to be qualified. The qualified type is corresponding to the combinations of one, two, or all three of the **const**, **volatile**, and **restrict** qualifiers.
> - Extensive reading on **38)**: [6.7.3 Type qualifiers](https://hackmd.io/yP9-qHGTRMOwyTNYBgaHzg?view#673-Type-qualifiers)
The qualified or unqualified versions of a type are distinct types that belong to the same type category and have the same representation and alignment requirements.[**39)**](http://port70.net/~nsz/c/c99/n1256.html#note39)
- [ ] A derived type is not qualified by the qualifiers (if any) of the type from which it is derived.
[27](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p27)
> imply `interchangeability` of the `type` pointed by a pointer: the same representation and alignment requirements
此 section 列出 interchangible 的 types,如下:
- `void *a` <-> `char *a`
- `qualified` or `unqualified` versions of compatible types
- const-qualified `float`
`const float *`
- `stucture` types
- `union` types
- other types
:notes: **need not** have the same representation or alignment requirement
[28](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p28) EXAMPLE 1
The type designated as ''float *'' has type ''pointer to float''. Its type category is pointer, not a floating type. The const-qualified version of this type is designated as ''float * const'' whereas the type designated as ''const float *'' is not a qualified type \-\- its type is ''pointer to const- qualified float'' and is a pointer to a qualified type.
> "float * const" — the pointer is *const-qualifed*
> "const float * " — its type is ‘‘pointer to constqualified float’’ and is a pointer to a qualified type
> > Qualifiers are applied on the immediate right type [name=@asahsieh] [color=red]
:book: more examples for different orders of qualifier and type
> from §6.5 CV修飾([cv(`const` and `volatile`) type qualifiers](https://en.cppreference.com/w/cpp/language/cv))的指標 in the book < C語言入門與進階教學 >
> by NCTU teacher < 鄭昌杰 >
可分為三種:
1. **CV修飾指標所指的==記憶空間==**。語法為修飾字放在 * 之前的任一位置:
- **CV修飾字** 型態名稱 * 指標名稱;
- 型態名稱 **CV修飾字** * 指標名稱;
2. **CV修飾==指標本身==**。語法為修飾字放在 * 與指標名稱之間:
:star: 再次提醒您,指標也是一種變數
- 型態名稱 * **CV修飾字** 指標名稱;
3. **CV修飾指標所指的==記憶空間==與==指標本身==**。語法為結合上述兩種方法:
- **CV修飾字** 型態名稱 * **CV修飾字** 指標名稱;
- 型態名稱 **CV修飾字** * **CV修飾字** 指標名稱;
接下來我們以`const`當作修飾字為例,在三種情況下,各別的範例如下:
:notes: 若以const修飾指標本身,*一定要給初始值*!
:::info
參考程式:https://github.com/asahsieh/linux-kernel-internals/tree/main/c-lang/type
:::
[29](http://port70.net/~nsz/c/c99/n1256.html#6.2.5p29)
EXAMPLE 2 The type designated as ''struct tag (*\[5\])(float)'' has type ''array of pointer to function returning struct tag''. The array has length five and the function has a single parameter of type float. Its type category is array.
### 6.7.2
#### 6.7.2.1 Structure and union specifiers
[2] A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself),
> :thinking_face: [6.2.5 Types ¶1](https://hackmd.io/MVSNZhEaQr2GXSwyom-odg#1)
> > **incomplete types** (types that describe objects but lack information needed to determine their sizes)
> > > e.g., `void` type
except that the last member of a structure with more than one named member may have incomplete array type;
- such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.
### [6.7.3 Type qualifiers](http://port70.net/~nsz/c/c99/n1256.html#6.7.3)
**Semantics**
[6](http://port70.net/~nsz/c/c99/n1256.html#6.7.3p6) An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in [5.1.2.3](http://port70.net/~nsz/c/c99/n1256.html#5.1.2.3). Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.[**116)**](http://port70.net/~nsz/c/c99/n1256.html#note116) What constitutes an access to an object that has volatile-qualified type is implementation-defined.
> 摘錄自< EFFECTIVE C > §volatile的[閱讀筆記](https://hackmd.io/MhVEcOc9QZS-9owoS6lGJA?both#volatile)
> > 告訴compiler此type的object的值在執行時會變動,以確保每次存取該物件的動作都會執行;否則,compiler若認為值不會變動,會做最佳化來跳過此次動作或利用上次讀到且快取值替代。
> > [name=@asahsieh] [color=red]
[7](http://port70.net/~nsz/c/c99/n1256.html#6.7.3p7) An object that is accessed through a restrict-qualified pointer has a special association with that pointer.
#### [6.7.3.1 Formal definition of `restrict`](http://port70.net/~nsz/c/c99/n1256.html#6.7.3.1)
:spiral_note_pad: Rule [EXP43-C. Avoid undefined behavior when using restrict-qualified pointers](https://wiki.sei.cmu.edu/confluence/display/c/EXP43-C.+Avoid+undefined+behavior+when+using+restrict-qualified+pointers)
from [SEI CERT C Coding Standard](https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard)
In the absence of this qualifier, other pointers can alias this object.
**Caching the value in an object designated through a `restrict`-qualified pointer is safe at the beginning of the block in which the pointer is declared** because no preexisting aliases may also be used to reference that object. The cached value must be restored to the object by the end of the block, where preexisting aliases again become available.
For a `restrict`-qualified pointer at file scope, the block is the body of each function in the file \[[Walls 2006](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography)\].
- :star: **Overlapping Objects**
:::info
The `restrict` qualifier requires that the pointers do not reference overlapping objects. If the objects referenced by arguments to functions overlap (meaning the objects share some common memory addresses), the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See also [undefined behavior 68](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_68).)
:::
- **Invoking Library Functions with `restrict`-Qualified Pointers**
**Ensure that `restrict`-qualified source and destination pointers do not reference overlapping objects when invoking library functions.**
For example, the following table lists C standard library functions that copy memory from a source object referenced by a `restrict`-qualified pointer to a destination object that is also referenced by a `restrict`-qualified pointer:
| Standard C | Annex K |
| ----------- | ------------- |
| `strcpy()` | `strcpy_s()` |
| `strncpy()` | `strncpy_s()` |
| `strcat()` | `strcat_s()` |
| `strncat()` | `strncat_s()` |
| `memcpy()` | `memcpy_s()` |
| | `strtok_s()` |
If data must be copied between objects that share common memory addresses, a copy function guaranteed to work on overlapping memory, such as `memmove()`, should be used.
- **Noncompliant Code Example**
In this noncompliant code example, the values of objects referenced by `ptr1` and `ptr2` become unpredictable after the call to `memcpy()` because their memory areas overlap:
```c
#include <string.h>
void func(void) {
char c_str[]= "test string";
char *ptr1 = c_str;
char *ptr2;
ptr2 = ptr1 + 3;
/* Undefined behavior because of overlapping objects */
memcpy(ptr2, ptr1, 6);
/* ... */
}
```
- **Compliant Solution**
In this compliant solution, the call to `memcpy()` is replaced with a call to `memmove()`. The `memmove()` function performs the same operation as `memcpy()` when the memory regions do not overlap. When the memory regions do overlap, the _n_ characters from the object pointed to by the source (`ptr1`) are first copied into a temporary array of _n_ characters that does not overlap the objects pointed to by the destination (`ptr2`) or the source.
```c
#include <string.h>
void func(void) {
char c_str[]= "test string";
char *ptr1 = c_str;
char *ptr2;
ptr2 = ptr1 + 3;
memmove(ptr2, ptr1, 6); /* Replace call to memcpy() */
/* ... */
}
```
---
### [6.7.4 Function specifiers](http://port70.net/~nsz/c/c99/n1256.html#6.7.4)
**Syntax**
[1](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p1)
```
function-specifier:
inline
```
> What and how: integrate that function’s code into the code for its callers. This makes execution faster by eliminating the function-call overhead - from [GCC 6.45](https://gcc.gnu.org/onlinedocs/gcc/Inline.html)
**Constraint**
[2](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p2)
Function specifiers shall be used only in the declaration of an identifier for a function.
> `identity` n. 識別符
> An identifier can denote an object; a function; a tag or a member of a structure, union, or enumeration; a typedef name; a label name; a macro name; or a macro parameter. The same identifier can denote different entities at different points in the program. [6.2.1 Scopes of identifiers p1](http://port70.net/~nsz/c/c99/n1256.html#6.2.1p1)
#### [3](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p3)
> 這邊用"shall not"表示spec沒有規定一定不行,
兩個各別條件如下:
1. *shall not* contain a **definition** of a modifiable object with static storage duration
> 不應包含一個可以修改儲存內容及靜態儲存區間的**物件**的定義(initializer)
2. *shall not* contain a **reference to an identifier** with internal linkage
> 不應參考到一個有內部連結的**識別字**
> > - *Review* meaning of `linkage`: [6.2.2§1 An identifier declared in different scopes or in the same scope more than once can be made to refer to the same object or function by a process called linkage](https://hackmd.io/MVSNZhEaQr2GXSwyom-odg?both#1-An-identifier-declared-in-different-scopes-or-in-the-same-scope-more-than-once-can-be-made-to-refer-to-the-same-object-or-function-by-a-process-called-linkage21-There-are-three-kinds-of-linkage-external-internal-and-none)
> > - a modifiable object → :question: means the type of the object is not a `const` type?
- [x] (Guess) 因為inline會將function複製多份一樣的code,若這些一樣的code同時執行的話,對靜態儲存區間的物件會有race condition的問題。
--> **Run the program!**
- Examples
1. the inline function with external linkage and the object with static storage durating are ++in the same translation unit++
> 練習的[程式碼](https://github.com/asahsieh/linux-kernel-internals/blob/main/clang/macro_and_inline/bbsort_inline.c)
> > the inline function: `bbsort()`
> > the static object: swap_cnt
此程式碼設計兩個情況,將swap_cnt宣告成`static`或`automatic` variable; 利用define `CONS_3_SAME_TRANS_UNIT` macro透過preprocessor來切換。
==兩種情況的結果一致:==
```shell
bbsort::swap_cnt=4
2 4 6 7 8 9
```
:thinking_face: 我們預期兩種情況的值應該會不一致;有沒有可能是因為`bbsort()`沒有被展開,因為只有被呼叫一次?
- 此書[^third]第9.4節 行內函式中,有一段**粗體字**說明編譯器面對行內涵式時的處理方式,摘錄如下:
:::info
編譯器在面對行內涵式時,會**嘗試**著將函式的程式碼內嵌在呼叫端。請注意,並不是所有的行內函式都能被內嵌成功。**一般情況,當函式內容只有為數不多的運算式時,才會被內嵌成功**。**若行內函式的內容包含了迴圈,或著其他非行內函式**,編譯器將有可能不會進行內嵌動作,而是視為一般的函式來看待。
:::
:notes: 此section的semantics [5](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p5)最後一句描述有提到: The extent to which such suggestions are effective is implementation-defined.[121)](http://port70.net/~nsz/c/c99/n1256.html#note121)
- 於是確認GCC對inline function的實做:
該節[6.45 An Inline Function is As Fast As a Macro](https://gcc.gnu.org/onlinedocs/gcc/Inline.html)的標題也呼應了semantics [5]中提到的如何達到as fast as possible.[121)](http://port70.net/~nsz/c/c99/n1256.html#note121)
:::spoiler 不會做 inline 的情況如下:
- if any of the actual argument values are constant --> be simplification at compile time
- When a function is both inline and static, if all calls to the function are integrated into the caller, and the function’s address is never used, then the function’s own assembler code is never referenced.
- If there is a nonintegrated call, then the function is compiled to assembler code as usual.
- Note that certain usages in a function definition can make it unsuitable for inline substitution. Among these usages are: variadic functions, use of alloca, use of computed goto, etc.
:::
GCC提供了一個option,讓user指導GCC**嘗試**嵌入所有 "simple enough" functions到它們的callers: `-finline-functions`
- 若非最佳化的話, GCC不inline任何functions;除非user明確指出該function有‘always_inline’ attribute:
```c
/* Prototype. */
inline void foo (const char) __attribute__((always_inline));
```
- 如何確認GCC是否有做inline?[How will i know whether inline function is actually replaced at the place where it is called or not?](https://stackoverflow.com/a/10631297)
我透過加上‘always_inline’ attribute到該function, 並透過上述連結提供檢查assembly code的方式,有觀察到`call swap`指令被取代。
> 編譯指令:
`gcc bbsort_inline.c -Winline -S`
> 觀察的檔案:
`bbsort_inline.s`
上述方式必須解析assembly code,於是使用另法,[觀察object file搭配source code](https://hackmd.io/bCphybK2Sg-To2gZrSOo4A#%E9%A1%AF%E7%A4%BA%E5%8E%9F%E5%A7%8B%E7%A2%BC%E5%B0%8D%E6%87%89),可看到`swap()`的source code被嵌入並置換掉`bbsort()`中呼叫`swap(A + i, A + j)`的statement,如下圖:

> 從嵌入的程式碼可以看到`GCC`將`swap()`做inline的方式,是將呼叫的該行程式碼置換成inline function內的程式碼;而非上述的猜想:「(Guess) 因為inline會將function複製多份一樣的code」,原來的nested loop沒有做loop unrolloing。
==所以兩種情況的值還是會一致==
- 2. the inline function with external linkage and the object with static storage durating are ++in the **different** translation units++
==該static object的值仍然一致==,可參考此[commit](https://github.com/asahsieh/linux-kernel-internals/blob/3ad7d3081fd2ddc38cc59fb32629d56aace6fdcd/clang/macro_and_inline)中的`sort.c`與`sort.h`
:notes: (TO-BE-TESTED) the value may be changed if we unroll the nested loop and execute iterations of the loop parallelly.
#### - [ ] (TO-CREATE-AN-EXAMPLE) [4](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p4) In a hosted environment, the inline function specifier shall **not** ==appear in a declaration of main==.
#### [6](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p6) Any function with internal linkage can be an inline function.
> 在[^third],亦有提到:行內函式還有一個重要特性,就是**它的可用範圍為一個編譯單元**, 以下用:notes:來註記。
==For a function with external linkage==, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit.
> 如果一個函式有外部連結,且宣告裡有inline函式說明符,則它的定義也應該在相同的編譯單元裡。
> :notes: 任何行內函式的宣告與定義必須存在於同一個編譯單元。
> > 參考此[commit](https://github.com/asahsieh/linux-kernel-internals/blob/3ad7d3081fd2ddc38cc59fb32629d56aace6fdcd/clang/macro_and_inline)中的`sort.c`、`sort.h`與`bbsort_inline_separate_files.c`
:::info
extern inline function `bbsort()` 的defintion是在*sort.c*中,若將他從GCC的compiling source list移除,只保留`main`function所在的source code及inline function的宣告:
```shell
gcc sort.h bbsort_inline_separate_files.c
```
則會出現找不到`bbsort()` *definition*的error:
```shell
/usr/bin/ld: /tmp/ccTkQZ4q.o: in function `main':
bbsort_inline_separate_files.c:(.text+0x9e): undefined reference to `bbsort'
collect2: error: ld returned 1 exit status
```
:::
If ++all of the file scope declarations++ for a function in a translation unit include the inline function specifier ==without extern==, then ++the definition++ in that translation unit is ==an inline definition==.
> 在一個編譯單元的一個函式,若該函式的所有"檔案範圍的宣告"(? TO-BE-CHECKED),包含行內的函式[說明符](https://terms.naer.edu.tw/detail/18130130/?index=3);則此函式在此編譯單元內的定義為一個**行內的定義**
> 如inline function的宣告與定義在同一個檔案的原始碼中對`inline static void bbsort()`的[註解](https://github.com/asahsieh/linux-kernel-internals/blob/main/clang/macro_and_inline/bbsort_inline.c#L32), 若該function的宣告有`inline`且沒有`extern`, 則該function在此translation unit的定義是一個*inline definition*。
An inline definition does not provide an *external definition* for the function, and :question: does not forbid an external definition in another translation unit.
> 延續上段描述;若該function的定義是一個inline定義,則沒有提供外部定義,但在其他編譯單元,則沒有禁止。
> 一個具有行內的定義的函式不能提供[外在定義];(http://port70.net/~nsz/c/c99/n1256.html#6.9)
> :notes: 行內函式在不同的編譯單元可以有不同的定義
- The example code, using a define macro to move the declaration of the function from header to each translation unit:
- header: *sort.h*
```c
#ifndef SEMANTICS_5_EXTERN_DEF_IN_ANTHER_TRNS_UNIT
inline static void swap(int *, int *);
#endif
```
- the inline definition: in *bbsort\_inline\_separate_files.c*
```c
#include "sort.h"
#ifdef SEMANTICS_5_EXTERN_DEF_IN_ANTHER_TRNS_UNIT
inline static void swap(int *, int *);
#endif
/* 屬於main的swap定義 */
void swap(int *pa, int *pb)
{
...
}
```
- an external definition in another translation unit: in
```c
#include "sort.h"
#ifdef SEMANTICS_5_EXTERN_DEF_IN_ANTHER_TRNS_UNIT
extern void swap(int *, int *);
#endif
/* 屬於sort.c的swap定義 */
void swap(int *pa, int *pb)
{
...
}
```
:question: An inline definition provides an alternative to an external definition,
which a translator may use to implement ==any call to the function in the same translation unit==. It is ==unspecified== whether a call to the function uses the inline definition or the external definition.
> 此描述的範例與解說在Semanitics[7](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p7)與Semantics[8](http://port70.net/~nsz/c/c99/n1256.html#6.7.4p8)
> 若有兩個相同名字的functions, 一個是inline定義,另一個是外部定義;則translator會使用兩者之一。
> :note: Reference **Aside Optimizing function calls by inline substitution** section in CS:APP chap 5
> > Unfortunately, gcc only attempts inlining for functions defined within a single file. That means it will not be applied in the common case where a set of library functions is defined in one file but invoked by functions in other files.
**Footnotes**
#### [120)](http://port70.net/~nsz/c/c99/n1256.html#note120)
> "inline subsitution": is not textual substitution, nor does it create a new function.
> > to achieve "as fast as possible", parallelly executing the calls by inline substitutions?
### [6.8 Statements and blocks](http://port70.net/~nsz/c/c99/n1256.html#6.8)
#### [3] A *block*
allows a set of declarations and statements to be grouped into one syntactic unit.
> syntactic unit: between left brace and the matching right brace (ref. 4.8 Block Structure in K&R C)
The initializers of objects that have automatic storage duration,
```
int x = 1;
```
and the variable length array declarators of ordinary identifiers with block scope,
```
int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
```
are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear.
[^first]: [ISO/IEC 9899 網頁版](http://port70.net/~nsz/c/c99/n1256.html#6.8)
[^second]: [Effective C by Robert C. Seacord, Released August 2020, Publisher(s): No Starch Press, ISBN: 9781718501041](https://www.oreilly.com/library/view/effective-c/9781098125677/)
[^third]: [C語言入門與進階教學:跨平台程式設計及最新C11語法介紹, 作者: 鄭昌杰, 公開日期: 2017, 出版社: 交大出版, ISBN: 9789866301988](https://ir.nctu.edu.tw/handle/11536/151785?locale=zh_TW)