如何在C/C++中减去两个IPv6地址(128位数)?

sha*_*man 6 c c++ networking ipv6

我正在存储sockaddr_in6支持四个32位数组addr [4]的IP地址.基本上是一个128位的数字.

我正在尝试计算给定IPv6范围内的IP数量(两者之间的IP数).所以这是使用两个长度为4的数组从一个减去另一个的问题.

问题是因为没有128位数据类型,我无法转换为十进制.

万分感谢!

Voi*_*tar 3

您可以使用某种 big-int 库(如果您可以容忍 LGPL,则选择 GMP)。幸运的是,如有必要,128 位减法很容易手动模拟。下面是计算 128 位值的 (ab) 绝对值的快速而简单的演示:

#include <iostream>
#include <iomanip>

struct U128
{
    unsigned long long hi;
    unsigned long long lo;
};

bool subtract(U128& a, U128 b)
{
    unsigned long long carry = b.lo > a.lo;
    a.lo -= b.lo;
    unsigned long long carry2 = b.hi > a.hi || a.hi == b.hi && carry;
    a.hi -= carry;
    a.hi -= b.hi;
    return carry2 != 0;
}

int main()
{
    U128 ipAddressA = { 45345, 345345 };
    U128 ipAddressB = { 45345, 345346 };

    bool carry = subtract(ipAddressA, ipAddressB);

    // Carry being set means that we underflowed; that ipAddressB was > ipAddressA.
    // Lets just compute 0 - ipAddressA as a means to calculate the negation 
    // (0-x) of our current value. This gives us the absolute value of the
    // difference.
    if (carry)
    {
        ipAddressB = ipAddressA;
        ipAddressA = { 0, 0 };
        subtract(ipAddressA, ipAddressB);
    }

    // Print gigantic hex string of the 128-bit value
    std::cout.fill ('0');
    std::cout << std::hex << std::setw(16) << ipAddressA.hi << std::setw(16) << ipAddressA.lo << std::endl; 
}
Run Code Online (Sandbox Code Playgroud)

这将为您提供差异的绝对值。如果范围不大(64 位或更少),那么ipAddressA.lo您的答案可以是简单的unsigned long long.

如果您有性能问题,您可以利用编译器内在函数来利用某些架构,例如 amd64(如果您希望它在该处理器上达到最佳效果)。_subborrow_u64是进行必要的减法运算的 amd64 内在函数。