#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;
}
这为您提供了差异的绝对值 . 如果范围不是很大(64位或更少),那么 ipAddressA.lo 可以作为一个简单的 unsigned long long 答案 .
2 回答
您可以使用某种big-int库(如果您可以容忍LGPL,则可以选择GMP) . 幸运的是,如果需要,可以手动模拟128位减法 . 这是一个快速而肮脏的演示,计算128位值的(a-b)的绝对值:
这为您提供了差异的绝对值 . 如果范围不是很大(64位或更少),那么
ipAddressA.lo
可以作为一个简单的unsigned long long
答案 .如果您有perf问题,可以使用编译器内在函数来利用某些体系结构,例如amd64,如果您希望它在该处理器上是最佳的 .
_subborrow_u64
是必要的减法工作的amd64内在函数 .in6_addr
结构以网络字节顺序存储地址 - 或'big endian' - 使用最高有效字节@s6_addr[0]
. 您不能指望其他联盟成员一致地命名或定义 . 即使您通过(非可移植)uint32_t
字段访问了联合,也必须使用ntohl
转换值 . 因此,找到差异的便携方法需要一些工作 .您可以将
in6_addr
转换为uint64_t[2]
. 坚持典型的'bignum'约定,我们使用[0]表示低64位,[1]表示高64位:和区别: