# 課前測驗題
( 返回 [2017年暑期系統軟體課程:台北場次](https://hackmd.io/s/BJRtkreHW) )
:::danger
:mega: 從下方至少選 3 題來作答,不僅要提供程式碼,也該描述思路。作答方式為建立「新的」HackMD 頁面,在「標題」提及自己的姓名或可資識別的代號,內文則應標註原題號,如 ==Q1:==,隨後將新建的 HackMD 連結貼入報名表格,課程工作人員會逐一通知。
* 參考: [HackMD 教學和作業原則](https://hackmd.io/s/Bk-1zqIte)
* 示範: [coldnew](https://github.com/coldnew/2015-embedded-summber-note)
:::
:::info
我們期望學員在參加系統軟體課程之前,能夠充分回答以下提問,不僅理解自身學習背景,也藉此和其他學員交流。 -- [jserv](http://wiki.csie.ncku.edu.tw/User/jserv)
:::
---
- [ ] Q1: 考慮以下 C99 程式,解釋其具體作用,並用 for/while 迴圈改寫,隨後提供 `uint16_t` 的版本。在什麼場合會用到下方的程式碼?
```C
#include <stdint.h>
uint32_t func(uint32_t x) {
uint32_t n = x;
n = ((n & 0xffff0000) >> 16) | ((n & 0x0000ffff) << 16);
n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);
n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
return n;
}
```
---
- [ ] Q2: 在 C 程式中,使用遞迴和 bit-wise operator 來實作乘法運算,請參考以下提示:
* 加法器是用於執行加法的電路元件,通常由 AND 閘、OR 閘 和 XOR 閘構成
- 也可用加法器實作減法,只要將減數轉成二補數,並注意溢位即可
* 半加器:將兩個一位二進位數相加 (input: A, B) (output: S, C)

* 全加器:將兩個一位二進位數相加 (input: A, B, Cin) (output: S, Cout)

* 波紋進位加法器:使用多個一位全加器構成 N 位加法器

* 半加器可用以下 C 程式來實作:
```c
uint32_t half_add(uint32_t a, uint32_t b) {
if (b == 0) return a;
uint32_t sum = a ^ b; /* 相加但不進位 */
uint32_t carry = (a & b) << 1; /* 進位但不相加 */
return half_add(sum, carry);
}
```
---
- [ ] Q3:思考以下 C 程式的用途,以及在什麼場合用得到 (提示: 記憶體管理常式),探討應用場合時,需要一併列出最小可編譯和運作的 C 程式碼。
```C
char *p;
...
*p = (*p) & ~1;
```
---
- [ ] Q4: 考慮以下 C 程式在 GNU/Linux 中,透過 linked list 來實作動態記憶體管理 (malloc 和 free),虛擬記憶體的使用如下圖,初步的程式如下方,要注意到程式碼並不完整,也不能在多執行緒環境安全運用。請改寫 `malloc` 程式碼使其正確運作,並提供對應的 `free` 實作。

```C
#include <stddef.h>
#include <unistd.h>
#include <pthread.h>
struct header_t {
size_t size;
unsigned is_free;
struct header_t *next;
} *head, *tail;
static struct header_t *
get_free_block(size_t size) {
struct header_t *curr = head;
while (curr) {
if (curr->is_free && curr->size >= size) return curr;
curr = curr->next;
}
return NULL;
}
pthread_mutex_t global_malloc_lock;
void *malloc(size_t size) {
size_t total_size;
void *block;
struct header_t *header;
if (!size) return NULL;
if ((header = get_free_block(size)) {
header->is_free = 0;
return ? /* FIXME */
}
total_size = sizeof(struct header_t) + size;
if ((block = sbrk(total_size)) == (void *) -1)
return NULL;
header = block;
header->size = size;
header->is_free = 0;
header->next = NULL;
... /* FIXME */
return ? /* FIXME */
}
```
---
- [ ] Q5: 假設下方 C 程式檔名為 `fork.c`,在 GNU/Linux 上編譯得到名為 `fork` 的執行檔,我們可用 `./fork | wc -c` 計算輸出的 `-` 字元,請解釋程式行為和輸出的 `-` 字元數量的關聯。
```C
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
for (int i = 0; i < 3; i++) {
fork();
printf("-");
}
wait(NULL); wait(NULL); wait(NULL);
return 0;
}
```
---