owned this note
owned this note
Published
Linked with GitHub
# GNU Compiler Collection (GCC)
[TOC]
> [online docs of GCC](https://gcc.gnu.org/onlinedocs/gcc/)
## [3 GCC Command Options](https://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html#Invoking-GCC)
### 3.13 Options Controlling the Preprocessor
> [online link](https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#Preprocessor-Options)
#### `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](https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions)
### 6.1 Statement Exprs
將多個敘述句(statement)視為一個運算式(expression), 且最後一個物件應該為一個`expression`跟著一個分號(;),++這個subexpression的值代表整個construct的值++
- 如以下expression, 表示`foo()`的結果的絕對值:
```c
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
```
> 變數`z`的值即為`foo()`的結果的絕對值
若改用大小括號( )取代分號(;), 則此construct的type為`void`,表示沒有值 (no value)
- :notes: 為什麼需要`statement expression`, 請參考"C99 - keywords/notes"中`巨集`的[閱讀筆記](https://hackmd.io/@asahsieh/C99-keywords_notes?view#-%E9%82%A3%E6%88%91%E5%80%91%E8%A9%B2%E6%80%8E%E6%A8%A3%E8%A8%AD%E8%A8%88%E4%B8%80%E5%80%8B%E5%B7%A8%E9%9B%86%E5%8F%AF%E4%BB%A5%E6%A8%A1%E6%93%AC%E6%9C%89%E5%9B%9E%E5%82%B3%E5%80%BC%E7%9A%84%E5%87%BD%E5%BC%8F)
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:
```c
#define max(a,b) ((a) > (b) ? (a) : (b))
```
:::warning
But this definition computes either a or b twice, with bad results if the operand has side effects.
:::
- [x] :question: 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,
```c
max(i++, j++)
```
我們從以下項目來觀察此macro的side effect:
1. Result of Macro substitution
> [原始碼](https://github.com/asahsieh/linux-kernel-internals/commit/cec40ea37b5e1df9f7bde31ed3d2bc9ebce0e748)
```c
#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`提供的`-E`option,只做preprocessing,來觀察macro置換的結果 ([ref.](https://hackmd.io/25hubldJSw6MyDKBZOrHYQ?view#gcc--E--o-out_filei-in_filec)):
> Command:
> ```shell
> gcc -E -o macro_eval_twice.i macro_eval_twice.c
> ```
- \~\~輸出結果\~\~:
```shell
# 7 "macro_eval_twice.c"
int main(int argc, char *argv[])
{
int i = 2, j = 3;
((i++) > (j++) ? (i++) : (j++));
return 0;
}
```
- 方法`2`: 透過`GDB`的`macro` command
> GDB doc ref.: [12 C Preprocessor Macros](https://sourceware.org/gdb/onlinedocs/gdb/Macros.html)
步驟如下:
- 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`的過程如下:
```shell=
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 statement`及`expression`, 其中expression用來做increment;並觀察執行該`if statement`前中後的變數的值的變化。
>
> 從[原始碼](https://github.com/asahsieh/linux-kernel-internals/blob/de881ba3108a5d0eb0baf6bcdff7823620b70ca9/practice/clang/macro_and_inline/statement_expresssion_in_gnu_c/macro_eval_twice.c)擷取上述說明對應的程式碼如下:
```c
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");
```
:notes: 執行結果如下:
```shell
=== 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)
```
:::success
可以觀察到,執行完if statement判斷後,i與j會被累加,接著,進到if statement後,會再執行`(i++);`,使得數值較大的變數會再被累加一次;如最後的warning message, 較大的值會從(3)變成(5)
:::
:accept: 以上回覆了此章節的第二個問題:
:question: What's the macro definition isn't safe?
關於第一個問題,:question: Why the above macro definition is “safe”?
> 此document page給的範例為:
>
> `#define max(a,b) ((a) > (b) ? (a) : (b))`
同上[原始碼](https://github.com/asahsieh/linux-kernel-internals/blob/de881ba3108a5d0eb0baf6bcdff7823620b70ca9/practice/clang/macro_and_inline/statement_expresssion_in_gnu_c/macro_eval_twice.c),有提供對應的程式碼來觀察此document給的範例:請參考`goto` label `TEST_MACRO_SAFE` 至 `END_OF_TEST` 的程式碼; 這裡列出執行結果如下:
```shell
=== 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)
:::warning
Note that introducing variable declarations (as we do in maxint) can cause variable shadowing
:::
```c
#define maxint(a,b) \
({int _a = (a), _b = (b); _a > _b ? _a : _b; })
```
- [x] :question: 有關`variable shadowing`的說明,請參考自我練習[K&R C Exercise 4-14](https://hackmd.io/@asahsieh/KnR-C#Exercise-4-14)的實作。
:notes: 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.
```c
static int a = ({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
```
:notes: 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).
:notes: 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,
```c
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 ](https://www.gnu.org/software/libtool/manual/html_node/Creating-object-files.html) in [Libtool](https://www.gnu.org/software/libtool/manual/html_node/index.html)
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`