比较三段式软件版本号大小

      服务端接收到客户端的请求,有时候需要对低于控制版本的客户端返回不同的结果。版本号一般是三段式的 "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;
    }
}

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注