contributed by < yiwei01
>
以下程式碼改寫自 Linux 核心,比較兩個 Ethernet MAC 地址是否一致。在特定的硬體平台 (如 Arm 和 MIPS) 可能會遇到 unaligned memory access,請改寫以避開這個問題。考慮輸入值必為 16-bit-aligned addresses
#include <stdint.h>
bool addr_equal(const uint8_t *addr1, const uint8_t *addr2)
{
uint32_t fold = ((*(const uint32_t *)addr1) ^ (*(const uint32_t *)addr2)) |
((*(const uint16_t *)(addr1 + 4)) ^ (*(const uint16_t *)(addr2 + 4)));
return fold == 0;
}
Hint: 考慮地址是 0x10003
Reference:
const uint16_t *a = (const uint16_t *)addr1, *b = (const uint16_t *)addr2;
return (0 == (a[0] ^ b[0]) | a[1] ^ b[1] | a[2] ^ b[2]));
使用 Linux 核心的 list.h,寫出對一個已經排序過的 linked list 做新增節點的操作。
Hint: list_empty, list_add, list_for_each_entry, list_add_tail
#include <stddef.h>
#include <stdint.h>
#include "list.h"
struct listitem {
uint16_t i;
struct list_head list;
};
static inline int cmpint(const void *p1, const void *p2) {
const uint16_t *i1 = (const uint16_t *) p1;
const uint16_t *i2 = (const uint16_t *) p2;
return *i1 - *i2;
}
void list_insert_sorted(struct listitem *entry, struct list_head *head)
{
struct listitem *item = NULL;
if (list_empty(head)) {
list_add(&entry->list, head);
return;
}
list_for_each_entry(item, head, list) {
if(item->i > entry->i){
list_add_tail(&entry->list, &item->list);
return;
}
}
list_add(&entry->list, head->next)
}
想法是:走訪 linked list 的同時做比較,符合比較的結果便直接插入。
注意:list_add
及 list_add_tail
的原始碼。
struct list_head *right = NULL;
INIT_LIST_HEAD(right);
list_for_each_entry_safe (item, is, &testlist, list) {
if(item->i > entry->i){
list_move_tail(&item->list,&right);
}
}
list_add(&entry->list,right);
list_splice_tail(right,head);
此版本雖然 worst case 雖然也是 O(n),但與上述 version1 的答案相比,較不直觀。
若不是 circular list ,則必須紀錄 front 及 rear ,因此在程式碼的撰寫上會多一些邊界條件判斷,以確保 front 及 rear 的正確性。
sysprog2019