功能需求
- 支持 2~36 進制轉換。
- 正數/零前綴
+,負數前綴 -。
- 8 進制前綴
0,16 進制前綴 0x/0X(可選大小寫)。
- 緩衝區溢出檢查,失敗返回
NULL。
核心實現
#define LOW_CASE_NUM 0
#define UP_CASE_NUM 1
#define MAX_STR_SIZE 128
// 輔助:除法取餘並更新被除數
static inline long num_div(long *n, int base) {
long r = *n % base;
*n /= base;
return r;
}
char *num_to_str(long num, int base, int case_sel, char *buf, size_t bufsz) {
if (base < 2 || base > 36) return NULL;
const char *digits = case_sel ? "0123456789abcdefghijklmnopqrstuvwxyz"
: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char sign = (num < 0) ? (num = -num, '-') : '+';
char tmp[MAX_STR_SIZE];
int i = 0;
tmp[i++] = '\0'; // 字符串結束符佔位
if (num == 0) {
tmp[i++] = '0';
} else {
while (num) tmp[i++] = digits[num_div(&num, base)];
}
// 添加進制前綴(低位在前,逆序構建)
switch (base) {
case 16: tmp[i++] = digits[33]; // 'x' 或 'X' (digits[33]='x', [34]='X' 需調整)
// 修正:直接用字面量更清晰
tmp[i++] = case_sel ? 'x' : 'X';
case 8: tmp[i++] = '0';
break;
}
tmp[i++] = sign; // 符號最後放(最高位)
if (i >= (int)bufsz) return NULL; // 溢出檢查
// 逆序複製到目標緩衝區
for (int j = 0; i >= 0; ++j, --i)
buf[j] = tmp[i];
return buf;
}
測試用例與輸出
int main() {
char buf[MAX_STR_SIZE];
char *p;
p = num_to_str(333, 16, LOW_CASE_NUM, buf, sizeof(buf)); // +0x14D
p = num_to_str(-333, 16, UP_CASE_NUM, buf, sizeof(buf)); // -0X14D
p = num_to_str(333, 8, LOW_CASE_NUM, buf, sizeof(buf)); // +0515
p = num_to_str(-333, 2, LOW_CASE_NUM, buf, sizeof(buf)); // -101001101
p = num_to_str(-333, 10, LOW_CASE_NUM, buf, sizeof(buf)); // -333
}
設計亮點
- 逆序構建:從低位向高位提取數字,自然避免了「先求長度再填充」的雙遍歷。
- 統一緩衝區:臨時數組
tmp 構建後一次性逆序複製,代碼緊湊。
- 參數校驗:基數範圍、緩衝區大小、符號處理完備。
- 大小寫可控:通過字符表選擇實現。
改進建議
- 16 進制前綴邏輯略顯生硬(
digits[33] 依賴具體字符表佈局),建議改為 case_sel ? 'x' : 'X'。
- 可擴展支持
unsigned long、long long 及自定義前綴風格(如無前綴、# 前綴)。
- 生產代碼建議加入
static assert 確保 MAX_STR_SIZE 足夠(64 位二進制含符號前綴需 66 字節)。