服務端接收到客戶端的請求,有時候需要對低於控制版本的客戶端返回不同的結果。版本號一般是三段式的 "xx.xx.xx",通常會將版本號解析成整數數字保存在 int arr[3] 數組中,然后逐個檢查數組中的數字;最常規的做法如下:
int compare_version(int client_version[3], int base_version[3])
{
if (client_version[0] > base_version[0]) {
return 1;
}
else if (client_version[0] == base_version[0]) {
if (client_version[1] > base_version[1]) {
return 1;
}
else if (client_version[1] == client_version[1]) {
if (client_version[2] > base_version[2]) {
return 1;
}
else if (client_version[2] == client_version[2]) {
return 0;
}
else {
return -1;
}
}
else {
return -1;
}
}
else {
return -1;
}
}
上面的代碼能夠正常運行,且沒有冗余的步驟;但是比較步驟較多,if 語句層層嵌套,代碼結構較為復雜。
本着“更短、更快、更強”的原則,開始思考能不能將代碼優化一下。
正常情況下,我們比較字符串“123”與“124”,都是從百位、十位、個位依次進行比價,就像上面的函數所做的那樣。而對於 int a = 123, int b = 124, 我們可以直接用 a > b、 a == b、a < b 來進行比較;所以,如果能夠把版本號的三個部分合並成一個更大的變量來進行比較,那么一步就可以比較出版本大小了。如何把三個 int 變量合並成一個更大的整形變量呢?
一個 int 變量占用4個字節,32個bit;如果能夠有一個 int96 的基本類型,那么可以這樣做:
int96 a,b;
a = *(int96*)client_version; //假設系統是 big-edian
b = *(int96*)base_version;
if (a > b) {
return 1;
}
else if (a == b) {
return 0;
}
else {
return -1;
}
但是C++中沒有占用96個bit的整數類型。
那么能不能將三個int放在一個int中呢?
考慮到市場上可以看到的各種軟件的版本號,對於主版本號.次版本號.編譯版本號,沒見過哪個版本號是超過100的;那么,用10個bit(最大值1023)來表示一個版本號是足夠的;所以,三段版本號可以分別用10個bit來表示,然后壓縮進一個32bit的int中。對於有符號的10個bit,其能表示的數字范圍為 -512 ~ 511,足夠我們使用的了。
如下兩個方法均可:
方法一
int compare_version(int client_version[3], int base_version[3])
{
int client = (client_version[0] << 20) | (client_version[1] << 10) | clien_version[2];
int base = (base_version[0] << 20) | (base_version[1] << 10) | base_version[2];
if (client > base) {
return 1;
}
else if (client == base) {
return 0;
}
else {
return -1;
}
}
方法二
int compare_version(int client_version[3], int base_version[3])
{
int diff = 0;
diff += (client_version[0] - base_version[0]) << 20;
diff += (client_version[1] - base_version[1]) << 10;
diff += (client_version[2] - base_version[2]);
if (diff > 0) {
return 1;
}
else if (diff == 0) {
return 0;
}
else {
return -1;
}
}