2016年12月11日 星期日

聯發科經典面試題

1. Explain "#error"



所以他就只是一個丟出錯誤訊息的 macro 而已。

2. Explain "struct" and "union"


在 C 中,我們可以利用 struct 來定義自己要的資料結構,例如說二維坐標中的一個點,可以用 struct Point {int x, y;};

同樣的我們也可以用 union 做類似的事情,只是差別在於, union 中的每個成員是共用同樣的記憶體。

3. Explain "volatile". Can we use "const" and "volatile" in the same variable? Can we use "volatile" in a pointer?


volatile 是告訴 compiler 不要擅自對變數作最佳化。

參考以下的 code:

int *x = FOO;
for (int i = 0; i < 100; ++i) {
    bar(i, x);
    *x = FOO;
}

其中 x 在迴圈外被初始化成 FOO (的值),先不管 FOO 是什麼,在迴圈內 compiler 發現 *x = FOO; 可以做一下最佳化讓 *x 不要給值這麼多次以增加執行效率,所以可能忽略 *x = FOO; 做的事情。

但是如果 FOO 是一個硬體的記憶體位置,每次取值可能不同的結果,那 compiler 擅自做了最佳化以後就會造成 *x 只從硬體的記憶體位置中取值取一次 (int *x = FOO;),為了避免這種事情發生,可以利用 volatile 加在 x 宣告的時候:

volatile int *x = FOO;

那 const 可以跟 volatile 一起使用嗎?當然囉,這兩個 keyword 的意思並沒有牴觸。const 的意思是 read-only 而不是不變的,volatile 的意思是他可能會變而不是你可以改他。

4. For the following C code

unsigned long v1 = 0x 00001111;
unsigned long v2 = 0x 00001202;
unsigned long v;
v = v1&(~v2);
v = v | v2;

ask: the value of v?

最後一個 v 可以展開一下:

v = v | v2
  = (v1 & (~v2)) | v2
  = ( v1 | v2 ) & ( ~v2 | v2 )

因為 ~v2 | v2 等於 1,所以展開後

v = v1 | v2 = 0x00001111 | 0x00001202 = 0x0001313

5. For the following C code

int a[5] ={1,2,3,4,5};
int *p = (int *)(&a+1);

ask: the value of *(a+1), (*p-1)?

*(a+1) 其實就是 a[1],所以就是 2;
(*p - 1) 就比較奇怪了,因為 (&a+1) 的關係所以 p 其實存的是 a[5] 的記憶體位置,
(a_pointer + a_number) = (a_pointer + (a_number * sizeof(*a_pointer)))
所以 &a + 1 = &a + 1 * sizeof(*&a) = &a + 1 * 20 = a[5] (這邊是假設 int 大小是 4 bytes)
所以理論上來說 *p 應該是 garbage,就算 - 1 以後還是 garbage ,答案應該是:不知道?


6. write a code

a. set the specific bit
b. clear the specific bit
c. inverse the specific bit (0->1; 1->0)

Macro 的解法:

a.
#define SET_BIT(x, n)      ((x) |=    (1 << (n)))
b.
#define CLEAR_BIT(x, n)    ((x) &= ~(1 << (n)))
c.
#define INVERSE_BIT(x, n)  ((x) ^=   (1 << (n)))

Function 解法:

a.
static inline void set_bit(int *x, int n) { *x |= (1 << n); }
b.
static inline void clear_bit(int *x, int n) { *x &= ~(1 << n); }
c.
static inline void inverse_bit(int *x, int n) { *x ^= (1 << n); }

7. Fill the blank

void(*(*papf)[3])(char *); // Rewrite this
typedef ___________;
pf(*papf)[3];


第三行最後是用 pf 把 *papf 當作參數傳進去,所以把中間的 (*papf)[3] 取出來變成 pf:

typedef void(*pf)(char *);



8. Write a code that check the input is a multiple of 3 or not without using division or mod


最蠢的方式當然就是寫一個迴圈一直減 3 然後看最後是不是剩下 0 ... 但是超沒效率 XD"

直覺想到一個比較好一點的方式是把全部位數相加,如果總和大於 10 的話就繼續做全部位數相加,值到剩下一位數為止,然後看是不是 0, 3, 6, 9,是的話就是 3 的倍數。但是沒辦法用 mod 所以不曉得怎麼取得每個位數 ... 所以大概只能用 sprintf 吧 XD

但實際講起來 sprintf 大概也是有用到除法或者 mod 吧 ...

目前看到有個比較可行的做法是,在 N base 的系統中測試能否被 (N+1) 整除的方式是將偶數位數的和跟奇數位數的和相減,再看是否能被 N+1整除。最常見的例子就是 11 啦,不過那是因為是在 10 base 的系統中,所以在 2 base (也就是 2 進位啦) 的系統中可以用這種方式來判斷是否為 3 的倍數。


int multiple_of_three(int num) {

    if (num < 0)
        num = -num;

    if (num == 0)
        return 1; // true
    if (num == 1 || num == 2)
        return 0; // false

    int even = 0, odd = 0;

    while (num != 0) {
        even += (num & 0x1);
        num >>= 1;
        odd += (num & 0x1);
        num >>= 1;
    }

    return multiple_of_three(even - odd);
}



9. Explain lvalue and rvalue.


lvalue 跟 rvalue 分別指的是 = (等號) 的左邊跟右邊的值,但這樣講不太精確,因為 lvalue 跟 rvalue 描述的是 expression 而不是 object:

C++03 3.10/1 says: "Every expression is either an lvalue or an rvalue."  It's important to remember that lvalueness versus rvalueness is a property of expressions, not of objects

lvalue 可以 reference, rvalue 不能 reference。


沒有留言:

張貼留言