C99 - keywords/note

Keywords

restrict

  • Origin: from C99 - Wiki #Design
    restrict qualification allows more aggressive code optimization, removing compile-time array access advantages previously held by FORTRAN over ANSI C[7]

  • Definition:

    Reference my study on the 6.7.3.1 Formal definition of restrict for detail.

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    Overlapping Objects
    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. (See also undefined behavior 68.)

Extensive reading: 真的理解 C 語言的 types 嗎?
by Jserv

static

reference 6.2.2 Linkage of identifiers

and the implication of static is mentioned on ¶3

inline

  • introduced in 6.7.4 in C99 and my study note on the section

  • From 〈C語言入門與進階教學〉- 鄭昌杰老師

    Example codes

    初始版本的程式碼為: bbsort_itr.c

    欲改進的函式bbsort(), 擷取程式碼如下:

    ​​void bbsort(int *A, size_t n) ​​{ ​​ size_t i, j; ​​ ​​ for (i = 0; i < n; i++) { ​​ for (j = i + 1; j < n; j++) { ​​ if (A[i] > A[j]) { ​​ int t = A[i]; /* Swap(A+i, A+j) */ ​​ A[i] = A[j]; ​​ A[j] = t; ​​ } ​​ } ​​ } ​​}
    • 9.3 巨集

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      還有什麼好方法可以*減少呼叫成本(e.g. 次數)*嗎?巨集(macro)或是個不錯的解決方案。

      改寫如下,原始碼請參考bbosrt_macro.c:

      ​​​​/* SWAP的巨集定義 */ ​​​​ ​​​​#define SWAP(a, b) \ ​​​​ { \ ​​​​ int t = a; \ ​​​​ a = b; \ ​​​​ b = t; \ ​​​​ } ​​​​ ​​​​void bbsort(int *A, size_t n) ​​​​{ ​​​​ size_t i, j; ​​​​ ​​​​ for (i = 0; i < n; i++) { ​​​​ for (j = i + 1; j < n; j++) { ​​​​ if (A[i] > A[j]) ​​​​ SWAP(A[i], A[j]); ​​​​ } ​​​​ } ​​​​}

      使用巨集雖然可以達到我們減少函式呼叫的成本的目標,但設計巨集要非常小心,它很容易帶來許多誤動作以及語法結構上的錯誤。 由於巨集是直接將內容取代於程式碼,您必須確保取代後的結果不會影響前後文的語法、運算邏輯與副作用(side effect)

      • 例如把SWAP裡的大括號去掉:

        ​​​​​​#define SWAP(a, b) \ ​​​​​​ int t = a; \ ​​​​​​ a = b; \ ​​​​​​ b = t;

        編譯時,加上ERR_INJ_INGNORING_BRACKETS這個定義。在GCC, 利用-D name, 可參考3.13 Options Controlling the Preprocessor

        對應命令為:gcc -o bbsort_macro.o -c -D ERR_INJ_INGNORING_BRACKETS bbsort_macro.c

        會有編譯上的錯誤,A[j]=t用了未宣告的變數t;完整的訊息如下:

        ​​​​​​bbsort_macro.c: In function ‘bbsort’:
        ​​​​​​bbsort_macro.c:19:5: error: expected expression before ‘int’
        ​​​​​​   19 |     int t = a;     \
        ​​​​​​      |     ^~~
        ​​​​​​bbsort_macro.c:31:17: note: in expansion of macro ‘SWAP’
        ​​​​​​   31 |                 SWAP(A[i], A[j]);
        ​​​​​​      |                 ^~~~
        ​​​​​​bbsort_macro.c:21:9: error: ‘t’ undeclared (first use in this function)
        ​​​​​​   21 |     b = t;
        ​​​​​​      |         ^
        ​​​​​​bbsort_macro.c:31:17: note: in expansion of macro ‘SWAP’
        ​​​​​​   31 |                 SWAP(A[i], A[j]);
        ​​​​​​      |                 ^~~~
        ​​​​​​bbsort_macro.c:21:9: note: each undeclared identifier is reported only once for each function it appears in
        ​​​​​​   21 |     b = t;
        ​​​​​​      |         ^
        ​​​​​​bbsort_macro.c:31:17: note: in expansion of macro ‘SWAP’
        ​​​​​​   31 |                 SWAP(A[i], A[j]);
        ​​​​​​      |                 ^~~~
        
        • true定義為零
          另外,編譯器不會檢查巨集定義的邏輯正確性,您有可能會不小心把某個"名詞"定義成錯誤的意義。如下:

          承上gcc的命令,只須將GCC選項中的定義改成ERR_INJ_SETTING_TRUE_0

          對應命令為:

          gcc -o bbsort_macro -D ERR_INJ_SETTING_TRUE_0 bbsort_macro.c

          Image Not Showing Possible Reasons
          • The image file may be corrupted
          • The server hosting the image is unavailable
          • The image path is incorrect
          • The image format is not supported
          Learn More →
          true定義帶入bbsort中比較相連的兩個陣列元素的判斷。程式修改的部份如下:

          ​​​​​​​​// warning: "true" redefined
          ​​​​​​​​// The order of sorted number will in DESCENDING order:
          ​​​​​​​​#ifdef ERR_INJ_SETTING_TRUE_0
          ​​​​​​​​#define true 0
          ​​​​​​​​#endif
          ​​​​​​​​
          ​​​​​​​​...
          ​​​​​​​​
          ​​​​​​​​void bbsort(int *A, size_t n)
          ​​​​​​​​{
          ​​​​​​​​    size_t i, j;
          ​​​​​​​​
          ​​​​​​​​    for (i = 0; i < n; i++) {
          ​​​​​​​​        for (j = i + 1; j < n; j++) {
          ​​​​​​​​#ifdef ERR_INJ_SETTING_TRUE_0
          ​​​​​​​​            if (A[i] > A[j] == true)
          ​​​​​​​​#else
          ​​​​​​​​            if (A[i] > A[j])
          ​​​​​​​​#endif
          ​​​​​​​​                SWAP(A[i], A[j]);
          ​​​​​​​​        }
          ​​​​​​​​    }
          ​​​​​​​​}
          

          > 可以觀察到這種巨集會造成所有邏輯都反過來了!
          於是bbsort並不會將陣列由小排大,而是由大排到小。加上error injection前跟後的結果如下:

          ​​​​​​​​$ gcc -o bbsort_macro bbsort_macro.c
          ​​​​​​​​
          ​​​​​​​​$ ./bbsort_macro
          ​​​​​​​​2 4 6 7 8 9 
          ​​​​​​​​
          ​​​​​​​​$ gcc -o bbsort_macro -D ERR_INJ_SETTING_TRUE_0 bbsort_macro.c
          ​​​​​​​​
          ​​​​​​​​$ ./bbsort_macro
          ​​​​​​​​9 8 7 6 4 2 
          

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      重點觀念:巨集並不是函式,所以巨集並沒有專用的回傳指令。

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      那我們該怎樣設計一個巨集可以模擬有回傳值的函式?

      這並沒有一個很好的方法,

      • 但若巨集內容是一個運算式回傳值就是該運算式的結果,那麼這個巨集就很像是一個有回傳值的函式。請看這個例子:

        ​​​​​​#define MIN(x, y) (x < y ? x : y)
        ​​​​​​
        ​​​​​​int main(void)
        ​​​​​​{
        ​​​​​​   ...
        ​​​​​​   m = MIN(a, b);
        ​​​​​​   ...
        ​​​​​​}
        

        此例中的MIN其實只是代表一個條件運算式

      • 如果巨集內容不是只有一個運算式,且回傳值是巨集裡的某個區域變數;C99沒有定義此語法,但GCC有提供一個敘述運算式(statement expression)來解決這個問題。

        若有數個敘述句,先以大括號包起後,再以小括號包住,那麼就會變成一個運算式,運算結果為最後一個敘述句的運算結果。請看下面這個例子:

        ​​​​​​#define MINA(A, n)          \
        ​​​​​​({                          \
        ​​​​​​    int x = A[0], i;        \
        ​​​​​​    for(i = 1; i < n; ++i); \
        ​​​​​​        x = MIN(x, A[i]);   \
        ​​​​​​    x;                      \
        ​​​​​​})
        

        Image Not Showing Possible Reasons
        • The image file may be corrupted
        • The server hosting the image is unavailable
        • The image path is incorrect
        • The image format is not supported
        Learn More →
        敘述運算式只有GCC支援,其他編譯器不一定有支援。

    • 9.4 行內函式
      提供「減少呼叫函式的次數來降低成本」的另一個方法;如上節所述,稍不小心就會設計出隱藏錯誤的巨集。

      inline是C99的一種特別的關鍵字,以inline所宣告的函式稱為行內函式(inline function),編譯器會將行內函式之定義內崁在呼叫的程式碼中,就好像巨集般的不需要呼叫成本

      更重要的是,行內函式能夠被檢查出編譯階段的錯誤。

      因為是置換原來宣告的function。

      設計行內函式有一個很重要的要求,
      很明確地告訴編譯器行內函式的連結方式(6.2.2 linkages of identifiers)。換句話說,您必須清楚地指示行內函式是內部連結還是外部連結;必須從下列兩種方式擇一宣告:

      1. 行內靜態函式
        函式宣告須以static指示;「函式宣告」或「函式定義」擇一以inline指示。

        呼應 C99 於 §6.7.4 Function specifier ¶6的定義

        Any function with internal linkage can be an inline function.

        若該function的identifier是file scope, 且包含static storage-class specifier,則該identifierinternal linkage - defined in [§6.2.2 ¶3]( )

      2. 行內外部函式
        函式宣告須以extern指示;「函式宣告」或「函式定義」擇一以inline指示。

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      延伸閱讀: external declaration

      inline是一個「建議」性質的關鍵字,是否能夠真正表現出「行內函式」應有的行為還是的取決於編譯器。

      • 若行內函式的內容包含了迴圈,或著呼叫其他非行內函式,編譯器將有可能不會進行內嵌的動作。

      行內函式還有一個重要特性,就是它的可用範圍為一個編譯單元,有三件事您必須注意:

      1. 任何行內函式的「宣告」與「定義」必須存在同一個編譯單元

        map Any function with internal linkage can be an inline function. ?

      2. 行內「靜態」函式在不同的編譯單元可以用不同的「定義」

        An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit.

      3. 行內「外部」函式的「定義」不可存在兩個以上的編譯單為內

        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.

External declaration/definition

  • From ¶5 of Semantics in C99 6.9:
    An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.140)
  • External declaration
    • From File Inclusion on the chapter The Compilation Process in〈EFFETIVE C〉
      Header files typically contain declarations for use by other programs. This is the most common way to share external declarations of functions and objects with other parts of the program.

    for a function, declartion is it's prototype

  • External definition

    the implementation of a function or an object

  • Other references:

    note on §1.10 External Variable and Scope in K&R C

  • An example
    ​​extern double fahr(double);                  // creates an external definition
    ​​double convert(int is_fahr, double temp)
    ​​{
    ​​      /* A translator may perform inline substitutions */
    ​​      return is_fahr ? cels(temp) : fahr(temp);
    ​​}
    

Translation unit

  • From [A.10 External Declarations] in K&R C
    The unit of input provided to the C compiler is called a translation unit; it consists of a sequence of external declarations, which are either declarations or function definitions.

  • From ISO C99
    translation unit, 5.1.1.1, 6.9

    參考先前閱讀 chap 5.1.1.1 筆記的結論:

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    綜合上述兩個註解;translation unit為一個source file, 且包含透過前置處理導引;前置處理器指示將外在宣告(External Declaration),headers和source files包含進來,(? not sure about the correctness of the statment)在程式執行時,再到對應的記憶體位置找對應的指令(利用symbol table)。

  • Examples from on §9 PREPROCESSOR in 〈EFFECTIVE C〉
    The Compilation Process

    • A preprocessing directive causes the preprocessor to take an action that might alter the resulting translation unit, meaning the code you write is often not the same code consumed by the translator. Compiler implementations usually provide a way to view the preprocessor output, called a translation unit, passed to the translator.

      Table 9-1: Outputting a Translation Unit

      Compiler Example command line
      Clang clang other-options -E -o output_file.i source.c
      GCC gcc other-options -E -o output_file.i source.c

    File Inclusion
    A powerful feature of the preprocessor is the ability to insert the contents of one source file into the contents of another source file by using the #include preprocessing directive.

    Table 9-2: Header File Inclusion

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

    Table 9-3: Transitive Header File Inclusion

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

Type-punning

In computer science, a type punning is any programming technique that subverts or circumvents the type system of a programming language in order to achieve an effect that would be difficult or impossible to achieve within the bounds of the formal language.

pun verb (puns, punning, punned) [no object]

make a joke exploiting the different possible meanings of a word: his first puzzle punned on composers, with answers like “Handel with care” and “Haydn go seek”.
雙關語

sub·vert

Undermine the power and authority of (an established system or institution).
顛覆傳統

cir·cum·vent

Find a way around (an obstacle).
利用他解,繞過程式語言的限制

In C and C++, constructs such as pointer type conversion and union

C++ adds reference type conversion and reinterpret_cast to this list — are provided in order to permit many kinds of type punning

  • 1 Sockets example
    One classic example of type punning is found in the Berkeley sockets interface.

    • The Berkeley sockets library fundamentally relies on the fact that in C, a pointer to struct sockaddr_in is freely convertible to a pointer to struct sockaddr;
      • reference: §6.2.5 Type ¶27

        imply interchangeability of the type pointed by a pointer: the same representation and alignment requirements 謝阿Sa

        此 section 列出 interchangible 的 types,如下:

        • void *a <-> char *a
        • qualified or unqualified versions of compatible types

          qualified adj.
          not complete or absolute; limited:

          • e.g., "pointer to const- qualified float" type descripted in ¶28

            ​​​​​​​​​​​const float *
            

            Image Not Showing Possible Reasons
            • The image file may be corrupted
            • The server hosting the image is unavailable
            • The image path is incorrect
            • The image format is not supported
            Learn More →
            const-qualified of pointer to float type:

            ​​​​​​​​​​​float * const 
            
        • stucture types
        • union types
        • other types
          Image Not Showing Possible Reasons
          • The image file may be corrupted
          • The server hosting the image is unavailable
          • The image path is incorrect
          • The image format is not supported
          Learn More →
          need not have the same representation or alignment requirement

    Often seen in the programming world is the use of "padded" data structures to allow for the storage of different kinds of values in what is effectively the same storage space.

    利用
    呼應上述提到的interchangibility;透過共用儲存空間,來降低記憶體的使用量。

  • Floating-point example
    However, supposing that floating-point comparisons are expensive, and also supposing that float is represented according to the IEEE floating-point standard, and integers are 32 bits wide, we could engage in type punning to extract the sign bit of the floating-point number using only integer operations:

bool is_negative(float x) {
    unsigned int *ui = (unsigned int *)&x;
    return *ui & 0x80000000;
}

  • By language
    • C and C++
      • Image Not Showing Possible Reasons
        • The image file may be corrupted
        • The server hosting the image is unavailable
        • The image path is incorrect
        • The image format is not supported
        Learn More →
        the above floating-point type-punning example also violates the C language's constraints on how objects are accessed:[3] the declared type of x is float but it is read through an expression of type unsigned int
      • On many common platforms, this use of pointer punning can create problems if different pointers are aligned in machine-specific ways.

Data structure alignment

在記憶體中,資料如何被安排及存取

  • It consists of three separate but related issues: data alignment, data structure padding, and packing.

    • Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      Alternatively, one can pack the structure, omitting the padding, which may lead to slower access, but uses three quarters as much memory.
  • Problems

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    Primitive data type

    • 組成其他data types的一組基本data types
    • 有些程式語言定義的data types, 處理器不一定有支援,或是用逼近的方式,如:
      • floating point

    The CPU accesses memory by a single memory word at a time. Aligned accesses will always access a single memory word. This may not be true for misaligned data accesses.

    If the highest and lowest bytes in a datum are not within the same memory word the computer must split the datum access into multiple memory accesses.

    This requires a lot of complex circuitry to generate the memory accesses and coordinate them. To handle the case where the memory words are in different memory pages

    • the processor must either verify that both pages are present before executing the instruction or be able to handle a TLB miss or a page fault on any memory access during the instruction execution.

      Some processor designs deliberately avoid introducing such complexity, and instead yield alternative behavior in the event of a misaligned memory access.

      e.g. implementations of the ARM architecture prior to the ARMv6 ISA require mandatory aligned memory access for all multi-byte load and store instructions.[8]

      the result of attempted misaligned access might be to round down the least significant bits of the offending address turning it into an aligned access

  • Data structure padding

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    Computing the maximum amount of padding required is more complicated, but is always less than the sum of the alignment requirements for all members minus twice the sum of the alignment requirements for the least aligned half of the structure members.

Note

Relation between object and identifier

object, 3.14

1 object

region of data storage in the execution environment, the contents of which can represent values

identifier, 6.4.2.1, 6.5.1

  • from 6.5.1 Primary expressions :
    2 An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator).[**79)**](http://port70.net/~nsz/c/c99/n1256.html#note79)

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    my note on lvalue
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    C Primary expressions

    Primary expressions are the building blocks of more complex expressions.
    Explaination in zh-tw: 識別字(identifier)是一個構件;構建塊(building block),提供它的宣告,用來指派一個物件(object) (在此情況,是一個lvalue)或是一個function (在此情況,它是一個function designator)。

Linkage

Frame Pointers

My note on RISC-V function: 3-Acquire-local-storage-resources-needed-for-function

My note on

Chapter 3: Machine-Level Representation of Programs

ASM:IA32 — IA32 programming

Struct and Union

A compiling error: flexible array member not at end of struct

  • The source code:
    ​​struct employee_info {
    ​​    ...
    ​​    char *name[];
    ​​    ...
    ​​}
    
  • Elaboration:
    • Check C99 std
    • Check books
  • Extended questions:
    • Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
      為什麼成員不可宣告成 incompleted type?