---
title: C語言
description:
---
# C語言
###### tags: `Interview`
## pointer
```c=
int a; // a integer
int *a; // a pointer to integer
int **a; // a pointer to pointer to a integer
int a[10]; // an array of 10 integer
int *a[10]; // an array of 10 pointer to integer
int (*a)[10]; // a pointer to an array of 10 integer
int (*a)(int); // a pointer to function(int) returning int
int (*a[10])(int); // an array of pointer to function(int) returning int
```
## function pointer
```c=
int (*f())
int *f()
```
* declare f as function *returning* **pointer to int**
```c=
int (*f)()
```
* declare f as **pointer to function** *returning* int
* 俗稱 : function pointer
```c=
int (*f())[];
```
* declare f as function *returning* **pointer to array of int**
```c=
int (*f())()[]
```
* declare f as function returning **pointer to function** *returning* array of int
```c=
int (*f[])()
```
* declare f as array of **pointer to function** returning int
* 俗稱 : function pointer array
### function ptr 小技巧
```c=
可將這個改成下面那樣
// use function pointer to declare
int operation(int a, int b, int (*operation)(int, int))
{
return operation(a, b);
}
這樣子比較容易閱讀
typedef int (*calculation)(int, int); // 之後宣告都可以用 calculation 就好
// use calculation to declare
int operation(int a, int b, calculation calc)
{
return calc(a, b);
}
```
## const
* [難懂的const關鍵字,const v.s. 指標](https://ithelp.ithome.com.tw/articles/10230783)
* const 通常表示只可讀取不可寫入的變數,常用來宣告常數。使用const有以下好處:
* 提升程式碼可讀性
* 使編譯器保護那些不希望被改變的參數
* 給優化器一些附加的資訊
* 編譯器處理方式 : define 在預處理階段展開;const 在編譯階段使用。
* 類型和安全檢查 : const 會在編譯階段會執行類型檢查,define 則不會。
* 存儲方式 : define 直接展開不會分配記憶體,const 則會在記憶體中分配。
```c=
char *const p2 = &c; // (const pointer to char) 限制不可以 改變地址本身
const char *p1 = &c; // (pointer to const char) 限制不可以透過地址去 改變變數的內容
```
## static
* `local`變數 : local 變數僅活在該函式內,存放位置在 stack 或 heap 記憶體中。
* `static`變數 : static變數生命周期(life time)跟程式一樣長,而範圍(scope)則維持不變,即在宣告的函式之外仍無法存取static變數。
* `global`變數 : 所有區段皆可使用此變數。
* http://ashinzzz.blogspot.com/2013/12/extern-static.html
* https://www.google.com/search?q=extern+static+function&oq=extern+static&aqs=chrome.1.69i57j0l5j69i60l2.4323j0j7&sourceid=chrome&ie=UTF-8
## volatile
* [volatile的正確用法](https://www.ptt.cc/bbs/C_and_CPP/M.1410942542.A.B3E.html)
* 由於嵌入式系統常處理 I/O、中斷、即時操作系統 (RTOS) 相關的問題,因此在嵌入式系統開發中 volatile 尤為重要。**被 volatile 修飾的變數代表它可能會被不預期的更新**,因此告知編譯器**不對它涉及的地方做最佳化**,並在每次操作它的時候都讀取該變數**實體位址**上最新的值,而不是讀取**暫存器**的值。
## inline vs macro
> macro 跟 inline 用 空間換取時間
> function 用時間換取空間
* inline 可以將修飾的函式設為行內函式,即像巨集 (macro) 一樣將該函式展開編譯,用來加速執行速度。
* inline 函數的參數類型被檢查,並進行必要的型態轉換。
```c=
#define B(N) (N+N+N)
int GetValue=7;
inline int ADD(int n){
return n+n+n;
}
int main()
{
int result1,result2;
result1 = B(GetValue);
result2 = ADD(GetValue);
printf("B=%d\n",result1);
printf("C=%d\n",result2);
return 0;
}
result1 會呼叫GetValue三次 來做N+N+N
result2 則是呼叫一次GetValue,然後再把三個加起來 這是兩個編譯時候的差異
然後inline還有一個問題就是,編譯器會自動判斷是否用inline展開函式合乎效益
例如若函式太長 然後在程式呼叫點中展開效果不那麼好 編譯器會忽略inline來做程式的編譯
```
## extern
* 可以聲明變數會在其它的位置被定義,這個位置可能是在同一份文件之中,或是在其它文件之中
* 看到「extern」,至少會讓「人」知道這個變數已經在別處定義了。
* 不能在使用extern時同時指定其值,必須先聲明extern找到變數,再重新指定其值
## [#error](https://www.itread01.com/content/1541838451.html)
* ```#error``` 預處理指令的作用是,編譯程式時,只要遇到 ```#error``` 就會生成一個編譯錯誤提示訊息,並停止編譯。其語法格式為:
```c=
// glibc中常見
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
```
>在 C 語言中,沒有內建的 try ... catch ... 控制結構,使用一般的控制結構來處理錯誤,類似第二種方式。但 C 語言本身沒有錯誤物件 (error object) 的概念,通常是藉由回傳常數來代表錯誤的狀態。
## [union vs structure](https://www.youtube.com/watch?v=KL65a0TyeYo)
* 在存儲多個成員信息時,編譯器會自動給struct第個成員分配存儲空間,struct 可以存儲多個成員信息,而Union每個成員會用同一個存儲空間,只能存儲最後一個成員的信息。
* union 乍看和 structure 有點像,但union內的屬性共用同一塊記憶體,故同一時間內僅能用union內其中一種屬性。union主要用來表示同概念但不同資料類型的實體。
* struct是不能用==跟!=來判斷是否相等的,因為struct的成員變數在記憶體空間裡面有可能是不連續的,但可以用=,若要比較兩個structure是否相等,要比較其中的每個element(element的比較可以用\== )
## typedef
* typedef保留字可以為資料型態建立別名,例如 ```typedef unsigned uint;```,之後uint就會被當作unsigned來看待
## lvalue vs rvalue
* 左值(lvalue):左值是保存在單一運算式之外的物件。您可以將左值當做具有名稱的物件。所有變數都是左值,包括不可修改的 (const) 變數。
* ++x
* 右值(rvalue):右值是暫存值,不會在使用它的運算式之外保存。
* x++
* 不會特別用一個變數去保存他的
## fopen vs open
* **fopen**:緩衝IO
* 緩衝IO,會先讀一塊到memory中,才不會每次要讀多少就讀一次,這樣會syscall好幾次。
* **open**:非緩衝IO
* 非緩衝IO,每次要讀多少,就要叫一次syscall。
## sizeof implementation
```c=
#define my_sizeof(x) ((char *)(&x+1) - (char *)(&x))
```
## attribute
```c=
__attribute((packed))__
// 如果**struct**加上**__attribute__((packed))**編譯器就不會做優化把大小用成2的倍數,會按照struct裡面原本的大小。
__attribute((aligned(16)))__
// 分配的空間會按照16bytes對齊
```
## # and ## Operators
* #會把後面接的字串,在pre-processor階段時加上""。
```c=
#include <stdio.h>
#define mkstr(s) #s
int main(void)
{
printf(mkstr(geeksforgeeks));
return 0;
}
output : geeksforgeeks
```
* ##則是把##前後的字串相接
```c=
#include <stdio.h>
#define concat(a, b) a##b
int main(void)
{
int xy = 30;
printf("%d", concat(x, y));
return 0;
}
output : 30
```