Try   HackMD

GNU Compiler Collection (GCC)

online docs of GCC

3 GCC Command Options

3.13 Options Controlling the Preprocessor

online link

gcc -E -o out_file.i in_file.c

Do preprocessing

-D name

Predefine name as a macro, with definition 1.

6 Extensions to the C Language Family

6.1 Statement Exprs

將多個敘述句(statement)視為一個運算式(expression), 且最後一個物件應該為一個expression跟著一個分號(;),這個subexpression的值代表整個construct的值

  • 如以下expression, 表示foo()的結果的絕對值:
    ​​​​({ int y = foo (); int z;
    ​​​​   if (y > 0) z = y;
    ​​​​   else z = - y;
    ​​​​   z; })
    

    變數z的值即為foo()的結果的絕對值 若改用大小括號( )取代分號(;), 則此construct的type為void,表示沒有值 (no value)

  • 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 →
    為什麼需要statement expression, 請參考"C99 - keywords/notes"中巨集閱讀筆記

This feature is especially useful in making macro definitions “safe” (so that they evaluate each operand exactly once). For example, the “maximum” function is commonly defined as a macro in standard C as follows:

#define max(a,b) ((a) > (b) ? (a) : (b))

But this definition computes either a or b twice, with bad results if the operand has side effects.

  • 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 →
    Why the above macro definition is “safe”, on the contrary, what's the macro definition isn't safe?

    K&R C 2nd 4.11.2 Macro Substitution有提及此陷阱(pitfall)及範例,如下:

    • Increment operators or input and output. For instance,
      ​​​​max(i++, j++)
      
      我們從以下項目來觀察此macro的side effect:
      1. Result of Macro substitution

        原始碼

        ​​​​​​​#include <stdio.h>
        ​​​​​​​
        ​​​​​​​#define max(a, b) ((a) > (b) ? (a) : (b))
        ​​​​​​​
        ​​​​​​​int main(int argc, char *argv[])
        ​​​​​​​{
        ​​​​​​​    int i = 2, j = 3;
        ​​​​​​​
        ​​​​​​​    printf("Before `max` comparison: i=%d, j=%d\n", i, j);
        ​​​​​​​    max(i++, j++);
        ​​​​​​​    printf("After `max` comparison:  i=%d, j=%d\n", i, j);
        ​​​​​​​
        ​​​​​​​    return 0;
        ​​​​​​​}
        
        • 方法1: 透過GCC提供的-Eoption,只做preprocessing,來觀察macro置換的結果 (ref.):

          Command:

          gcc -E -o macro_eval_twice.i macro_eval_twice.c
          
          • ~~輸出結果~~:
            ​​​​​​​​​​​# 7 "macro_eval_twice.c"
            ​​​​​​​​​​​int main(int argc, char *argv[])
            ​​​​​​​​​​​{
            ​​​​​​​​​​​    int i = 2, j = 3;
            ​​​​​​​​​​​    ((i++) > (j++) ? (i++) : (j++));
            ​​​​​​​​​​​
            ​​​​​​​​​​​    return 0;
            ​​​​​​​​​​​}
            
        • 方法2: 透過GDBmacro command

          GDB doc ref.: 12 C Preprocessor Macros

          步驟如下:

          • Now, we compile the program using the GNU C compiler, GCC. We pass the -gdwarf-214 and -g3 flags to ensure the compiler includes information about preprocessor macros in the debugging information. $ gcc -gdwarf-2 -g3 macro_eval_twice.c -o macro_eval_twice

          • Now, we start GDB on our sample program: $ gdb -nw ./macro_eval_twice

          • We can expand macros and examine their definitions, even when the program is not running.

            • 使用gdb的過程如下:

              ​​​​​​​​​​​​​Reading symbols from ./macro_eval_twice... ​​​​​​​​​​​​​(gdb) list main ​​​​​​​​​​​​​1 #include <stdio.h> ​​​​​​​​​​​​​2 ​​​​​​​​​​​​​3 #define max(a, b) ((a) > (b) ? (a) : (b)) ​​​​​​​​​​​​​4 ​​​​​​​​​​​​​5 int main(int argc, char *argv[]) ​​​​​​​​​​​​​6 { ​​​​​​​​​​​​​7 int i = 2, j = 3; ​​​​​​​​​​​​​8 ​​​​​​​​​​​​​9 printf("Before `max` comparison: i=%d, j=%d\n", i, j); ​​​​​​​​​​​​​10 max(i++, j++); ​​​​​​​​​​​​​(gdb) info macro max ​​​​​​​​​​​​​Defined at /home/asahsieh/Documents/Courses/Linux_Kernel_Design/linux-kernel-internals/practice/clang/macro_and_inline/statement_expresssion_in_gnu_c/macro_eval_twice.c:3 ​​​​​​​​​​​​​#define max(a, b) ((a) > (b) ? (a) : (b)) ​​​​​​​​​​​​​(gdb) macro expand max ​​​​​​​​​​​​​expands to: max ​​​​​​​​​​​​​(gdb) macro expand max(i++, j++); ​​​​​​​​​​​​​expands to: ((i++) > (j++) ? (i++) : (j++)); ​​​​​​​​​​​​​(gdb) macro expand max(2, 3); ​​​​​​​​​​​​​expands to: ((2) > (3) ? (2) : (3));

              從18, 19行的指令跟結果,可以觀察到跟方法1一樣置換後的結果;但無法觀察macro中expression的值,e.g. (2) > (3)?, 故,我將macro expand的結果拆解成if statementexpression, 其中expression用來做increment;並觀察執行該if statement前中後的變數的值的變化。

              原始碼擷取上述說明對應的程式碼如下:

              ​​​​​​​​​​​​​int main(int argc, char *argv[])
              ​​​​​​​​​​​​​{
              ​​​​​​​​​​​​​    int i = 2, j = 3, k, l, tmp;
              ​​​​​​​​​​​​​    printf("=== To test the macro with inputs causing \"pitfall\"");
              ​​​​​​​​​​​​​    printf(", `max(i++, j++)`===\n");
              ​​​​​​​​​​​​​
              ​​​​​​​​​​​​​    ...
              ​​​​​​​​​​​​​        
              ​​​​​​​​​​​​​        k = i;
              ​​​​​​​​​​​​​        l = j;
              ​​​​​​​​​​​​​        printf("Before the comparison:\ti=%d, j=%d\n", k, l);
              ​​​​​​​​​​​​​        if ((i++) > (j++)) {
              ​​​​​​​​​​​​​            printf("In the comparison:\ti=%d, j=%d\n", i, j);
              ​​​​​​​​​​​​​            (i++);
              ​​​​​​​​​​​​​            if (i == (k + 2)) {
              ​​​​​​​​​​​​​                printf("[WARN] The expression are evaluated twice.\n");
              ​​​​​​​​​​​​​                printf("The larger value (%d) is incremented twice to (%d)\n\n",
              ​​​​​​​​​​​​​                       k, i);
              ​​​​​​​​​​​​​                goto EXANGE_INPUTS;
              ​​​​​​​​​​​​​            }
              ​​​​​​​​​​​​​
              ​​​​​​​​​​​​​        }
              ​​​​​​​​​​​​​    
              ​​​​​​​​​​​​​        ...
              ​​​​​​​​​​​​​            
              ​​​​​​​​​​​​​        printf("The macro is evaluated safely.\n\n"); 
              

              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 →
              執行結果如下:

              ​​​​​​​​​​​​​=== To test the macro with inputs causing "pitfall", `max(i++, j++)`===
              ​​​​​​​​​​​​​Before the comparison:  i=2, j=3
              ​​​​​​​​​​​​​In the comparison:      i=3, j=4
              ​​​​​​​​​​​​​[WARN] The expression are evaluated twice.
              ​​​​​​​​​​​​​The larger value (3) is incremented twice to (5)
              

              可以觀察到,執行完if statement判斷後,i與j會被累加,接著,進到if statement後,會再執行(i++);,使得數值較大的變數會再被累加一次;如最後的warning message, 較大的值會從(3)變成(5)

              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 →
              What's the macro definition isn't safe?

              關於第一個問題,

              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 →
              Why the above macro definition is “safe”?

              此document page給的範例為:

              #define max(a,b) ((a) > (b) ? (a) : (b))

              同上原始碼,有提供對應的程式碼來觀察此document給的範例:請參考goto label TEST_MACRO_SAFEEND_OF_TEST 的程式碼; 這裡列出執行結果如下:

              ​​​​​​​​​​​​​=== To test the macro with inputs make it "safe", `max(i,j)` ===
              ​​​​​​​​​​​​​Before the comparison:  i=4, j=7
              ​​​​​​​​​​​​​In the comparison:      i=4, j=7
              ​​​​​​​​​​​​​The macro is evaluated safely.
              ​​​​​​​​​​​​​The larger value after the comparion (7) is equalled to the orginal value (7)
              

              每個運算元只有被求值(evaluate)一次;上一個"unsafe"的例子,因為求值兩次,產生旁效應(side effect)

Note that introducing variable declarations (as we do in maxint) can cause variable shadowing

#define maxint(a,b) \
  ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
  • 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 →
    有關variable shadowing的說明,請參考自我練習K&R C Exercise 4-14的實作。

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 →
Embedded statements are not allowed in constant expressions

such as the value of an enumeration constant, the width of a bit-field, or the initial value of a static variable.

static int a = ({ int y = foo (); int z;
                if (y > 0) z = y;
                else z = - y;
                z; })

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 →
If you don’t know the type of the operand, you can still do this, but you must use typeof or __auto_type (see Typeof).

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 →
Jumping into a statement expression with goto or using a switch statement outside the statement expression with a case or default label inside the statement expression is not permitted. Jumping into a statement expression with a computed goto (see Labels as Values) has undefined behavior. Jumping out of a statement expression is permitted, but if the statement expression is part of a larger expression then it is unspecified which other subexpressions of that expression have been evaluated except where the language definition requires certain subexpressions to be evaluated before or after the statement expression.

  • For example,
    ​​foo (), (({ bar1 (); goto a; 0; }) + bar2 ()), baz();
    

    calls foo and bar1 and does not call baz but may or may not call bar2. If bar2 is called, it is called after foo and before bar1.

My notes

Creating object files

ref. 3.1 creating object files in Libtool

To create an object file from a source file, the compiler is invoked with the -c flag (and any other desired flags):

burger$ gcc -g -O -c main.c