Try   HackMD

2022q1 Homework (quiz3)

contributed by < hankluo6 >

第 3 週測驗題

測驗 1

運作原理

#define GENMASK(h, l) \
    (((~0UL) >> (LEFT)) & ((~0UL) >> (l) << (RIGHT)))

(~0UL) >> (LEFT) 將所有 bit 向右移,所以其 MSB 數來 bit 為 0 的數目與 LEFT 相等。可推出 (~0UL) >> (l) << (RIGHT) 需將從 LSB 數來的 bit 設為 0。

可得 LEFT = 63 - h(~0UL) >> (l) << (RIGHT) 需把 LSB 部分的 bit 清空,故 RIGHT = l


測驗 3

運作原理

#include <stdint.h> uint8_t rev8(uint8_t x) { x = (x >> 4) | (x << 4); x = ((x & 0xCC) >> 2) | (EXP2); x = ((x & 0xAA) >> 1) | (EXP3); return x; }

(x >> 4) | (x << 4) 將前四個位元與後四個位元交換,((x & 0xCC) >> 2) | (EXP2) 應要將每兩個位元互換,0xCC 表示將 3, 4, 7, 8 個位元又移,則須將 0xFF ^ 0xCC = 0x33 的位元左移,得 EXP2 = (x & 0x33) << 2((x & 0xCC) >> 2) | (EXP2) 將每一個位元互換,0xFF ^ 0xAA = 0x55,故 EXP2 = (x & 0x55) << 1


測驗 3

運作原理

#define foreach_int(i, ...)                                            \
    for (unsigned _foreach_i = (((i) = ((int[]){__VA_ARGS__})[0]), 0); \
         _foreach_i < sizeof((int[]){__VA_ARGS__}) / sizeof(int);      \
         (i) = ((int[]){__VA_ARGS__, 0})[EXP4])

利用 Variadic Macros 實現 foreach,其中 _foreach_i 用來記錄迴圈的次數,i 為目前的可變參數。

unsigned _foreach_i = (((i) = ((int[]){__VA_ARGS__})[0]), 0 剛進入迴圈時,透過 (i) = ((int[]){__VA_ARGS__})[0]i 設定為可變參數的第一個 element,並使用 , operator 將 _foreach_i 設定為 0。

迴圈的條件式 _foreach_i < sizeof((int[]){__VA_ARGS__}) / sizeof(int)_foreach_i 小於可變參數大小。

(i) = ((int[]){__VA_ARGS__, 0})[EXP4] 則需要得到下個可變參數,故 EXP4 = ++_foreach_i。另外 _foreach_i 會在可變參數大小後額外加一,才會跳出迴圈,故 (int[]){__VA_ARGS__, 0} 多一個 0 取不到陣列的值。

#define foreach_ptr(i, ...)                                                 \
    for (unsigned _foreach_i =                                              \
             (((i) = (void *) ((typeof(i)[]){__VA_ARGS__})[0]), 0); \
         (i); (i) = (void *) ((typeof(i)[]){__VA_ARGS__,            \
                                                    NULL})[EXP5],   \
                  _foreach_no_nullval(_foreach_i, i,                        \
                                      ((const void *[]){__VA_ARGS__})))

foreach_ptr 相同,只是迴圈終止條件改為判斷 i 是否為 null,而 i 會在跑完可變變數時被設為 null,故 EXP5 = ++_foreach_i