# 2018q3 第 17 週測驗題 (上) ### 測驗 `1` 考慮以下 C 程式: ```clike int x = 2; int main() { int x = 1; { extern int x; return x; } } ``` 執行後程式返回值 (program exit code, 用 `echo $?` 可得知) 為何? ==作答區== * `(a)` 2 * `(b)` 1 * `(c)` 0 * `(d)` 沒定義 :::success 延伸問題: 查閱相關 C 語言規格解釋,並探討對應的資訊安全問題 ::: --- ### 測驗 `2` 考慮以下 C 程式: ```clike typedef struct { char *key; char *value; } T1; typedef struct { long type; char *value; } T2; T1 a[] = { [1] = { "", ((char *) &((T2) {2, (char *) 3})), } }; int main() { T2 *p = (T2 *) a[1].value; return (int) p->value; } ``` 執行後程式返回值為何? ==作答區== * `(a)` 1 * `(b)` 2 * `(c)` 3 * `(d)` 標準沒有定義 :::success 延伸問題: 查閱相關 C 語言規格解釋,並探討對應的資訊安全問題 ::: --- ### 測驗 `3` 考慮以下程式碼,預期的 UNIX 終端機輸出為何? ```clike #include <stdio.h> unsigned long foo() { return (unsigned long) - 1 / 8; } int main() { printf("%d\n", (signed) foo()); } ``` ==作答區== * `(a)` 1 * `(b)` 0 * `(c)` -1 * `(d)` 標準沒有定義 :::success 延伸問題: 從 C 編譯器的角度,解釋為何如此 ::: --- ### 測驗 `4` 考慮以下 64-bit GCD (greatest common divisor, 最大公因數) 求值函式: ```clike #include <stdint.h> uint64_t gcd(uint64_t u, uint64_t v) { if (!u || !v) return u | v; while (v) { uint64_t t = v; v = u % v; u = t; } return u; } ``` 改寫為以下等價實作: ```clike #include <stdint.h> uint64_t gcd(uint64_t u, uint64_t v) { if (!u || !v) return u | v; int shift; for (shift = 0; !((u | v) & 1); shift++) { u /= 2, v /= 2; } while (!(u & 1)) u /= 2; do { while (!(v & 1)) v /= 2; if (u < v) { v -= u; } else { uint64_t t = u - v; u = v; v = t; } } while (K1); return K2; } ``` 補完以上程式碼。 ==作答區== K1 = ? * `(a)` u * `(b)` v * `(c)` u - v * `(d)` v - u * `(e)` u & 1 * `(f)` v & 1 K2 = ? * `(a)` u * `(b)` v * `(c)` u - v * `(d)` v - u * `(e)` u >> shift * `(f)` v >> shift * `(g)` u << shift * `(h)` v << shift --- ### 測驗 `5` 承測驗 `4`, 透過 gcc 內建的 [\_\_builtin_ctz](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) (Returns the number of trailing 0-bits in x, starting at the least significant bit position) 改寫程式碼如下: ```clike #include <stdint.h> uint64_t gcd(uint64_t u, uint64_t v) { if (!u || !v) return u | v; int shift = __builtin_ctzll(Z1); u >>= __builtin_ctzll(u); while (v) { v >>= __builtin_ctzll(v); if (u < v) { v -= u; } else { uint64_t t = u - v; u = v, v = t; } } return Z2; } ``` 補完以上程式碼。 ==作答區== Z1 = ? * `(a)` u * `(b)` v * `(c)` u & v * `(d)` v | u * `(e)` u & 1 * `(f)` v & 1 Z2 = ? * `(a)` u * `(b)` v * `(c)` u - v * `(d)` v - u * `(e)` u >> shift * `(f)` v >> shift * `(g)` u << shift * `(h)` v << shift :::success 延伸問題: 解釋上述程式程式運作原理,以及在 x86_64 上透過 [\_\_builtin_ctz](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) 改寫 GCD 對效能的提升 :::