---
# System prepended metadata

title: C語言
tags: [Interview]

---

---
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
```