中國大陸身份證號從 15 位升級為 18 位,核心變化:
19 或 20,歷史數據多為 19)。X(代表 10)。19 作為出生年份前兩位。S = Σ(本體碼[i] × 權重[i]),i=0..16。權重陣列固定:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2}。mod = S % 11。{'1','0','X','9','8','7','6','5','4','3','2'},索引為 mod。#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int id15_to_18(char *cert_no) {
if (!cert_no || strlen(cert_no) != 15) return -1; // 輸入校驗
static const int weight[17] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
static const char check_code[11] = {'1','0','X','9','8','7','6','5','4','3','2'};
char id18[19] = {0};
// 1. 拼接前 17 位
strncpy(id18, cert_no, 6); // 地址碼
strcat(id18, "19"); // 年份前綴
strncat(id18, cert_no + 6, 9); // 月日順序碼
// 2. 加權求和
int sum = 0;
for (int i = 0; i < 17; i++) {
if (id18[i] < '0' || id18[i] > '9') return -2; // 非數字字符
sum += (id18[i] - '0') * weight[i];
}
// 3. 校驗碼
id18[17] = check_code[sum % 11];
id18[18] = '\0';
// 4. 回寫
strcpy(cert_no, id18);
return 0;
}
int main() {
char id[20] = "320521720807225"; // 15 位測試樣本
printf("原始: %s\n", id);
if (id15_to_18(id) == 0) {
printf("升級: %s\n", id); // 預期: 320521197208072253
} else {
printf("轉換失敗\n");
}
return 0;
}
\0)。19;若涉及 2000 年後出生者,需額外邏輯判斷(如第 7、8 位月份 > 12 則可能為 20xx,但 15 位身份證最晚發放至 1999 年,通常固定 19 即可)。X:輸出為大寫字母 X,非小寫 x。bool validate_id18(const char *id) {
if (!id || strlen(id) != 18) return false;
int sum = 0;
for (int i = 0; i < 17; i++) {
if (id[i] < '0' || id[i] > '9') return false;
sum += (id[i] - '0') * weight[i];
}
char expected = check_code[sum % 11];
char actual = id[17];
return (expected == actual) || (expected == 'X' && actual == 'x'); // 兼容小寫 x
}
此實現簡潔、標準、無依賴,適合嵌入式、舊系統改造、數據清洗等場景直接嵌入使用。