2

嗨,我正在尝试将 4 个整数连接为一个整数。我使用了在这里找到的连接函数:

https://stackoverflow.com/a/12700533/2016977

我的代码:

unsigned concatenate(unsigned x, unsigned y) {
    unsigned pow = 10;
    while(y >= pow)
        pow *= 10;
    return x * pow + y;        
}

void stringtoint(){
    struct router *ptr;
    ptr=start;

    while(ptr!=NULL){
        int a;
        int b;
        int c;
        int d;

        sscanf(ptr->ip, "%d.%d.%d.%d", &a, &b, &c, &d);
        int num1 = concatenate(a,b);
        int num2 = concatenate(c,d);
        int num3 = concatenate(num1,num2);
        printf("%d\n",num3);
        ptr=ptr->next;
    };

}

问题:

我正在处理IP地址数字,例如198.32.141.140我将它们分解为4个整数并将它们连接起来形成 19832141140,但是我的连接函数正在对较大的数字进行数学运算,例如198.32.141.140(变为)->-1642695340 但它连接的是小数字的IP,例如164.78.104.1变成164781041(这是正确的)

我应该如何解决这个问题,基本上我正在尝试将一串 IP 例如变成198.32.141.140一个整数19832141140

4

3 回答 3

12

您提出的方法可能是一个很大的错误。你如何127.0.1.1区分127.0.0.11

将 IP 地址完全按照它们的本来面目对待要好得多。即,a.b.c.d表示

a * 256^3 + b * 256^2 + c * 256^1 + d * 256^0

并以这种方式完成,您不可能遇到我刚才描述的问题。此外,实现很简单:

unsigned int number;
number = (a << 24) + (b << 16) + (c << 8) + d
于 2013-08-17T16:37:58.357 回答
3

您可以阅读一行,然后使用inet_aton(). 否则,您可以按照 Jason 所说的那样做,但您需要检查每个整数值是否在 0 ... 255 范围内(那些 4 x 8 位表示包含 IPv4 地址的 32 位整数)。inet_aton()将支持 IPv4 地址的十六进制、十进制和八进制表示法。

于 2013-08-17T16:41:25.210 回答
1
/**
 ** You DO NOT want to do this usually...
 **/
#include <stdint.h>

uint_fast64_t
concatIPv4Addr(uint_fast16_t parts[])
{
    uint_fast64_t n = 0;

    for (int i = 0; i < 3; ++i) {
        n += parts[i];
        n *= 1000;
    }

    return (n += parts[3]);
}

我使用“快速”整数类型来提高速度,但如果您有存储要求,请改用相应的“最少”类型。当然,这假设您拥有 C99 编译器或带有扩展的 C89 编译器。否则你会被原始类型困住,char根据 C 标准,a 甚至可能是 32 位的。由于我不知道您的目标环境,因此我没有做任何假设。随意更改为您认为合适的适当原始类型。

我使用了一个 16 位的值(最小值),因为 8 位的数字只能代表 0-255,也就是说如果不小心输入了 358,它会被解释为 102,仍然有效。如果您有一个类型能够存储多于 8 位且少于 16 位,您显然可以使用它,但该类型必须能够存储多于 8 位。

除此之外,您至少需要一个 38 位类型:

4294967295 (32-bit unsigned max)
255255255255 (255.255.255.255 converted to the integer you want)
274877906944 (38-bit unsigned max)

上面的函数会将 127.0.1.1 和 127.0.0.11 分别转换为 127000001001 和 127000000011:

127.0.1.1 ->
127.000.001.001 ->
127000001001

127.0.0.11 ->
127.000.000.011 ->
127000000011

为什么这么多零?因为否则你无法分辨它们之间的区别!正如其他人所说,您可能会混淆 127.0.1.1 和 127.0.0.11。使用上面的函数或更合适的函数将 IPv4 地址实际转换为其真正的十进制表示,您将不会遇到这样的问题。

最后,我没有对传递给函数的 IPv4 地址进行验证。我假设您在调用任何保存或使用 IPv4 地址的函数之前已经确保该地址有效。顺便说一句,如果你想为 IPv6 做同样的事情,你不能那么容易,因为这需要一个字符串或将 8 个部分中的每一个转换为十进制,每个部分最多为 16 位,产生 5 个十进制数字每个部分,或 40 位数字。要存储它,您至少需要 133 位,而不是 IPv6 地址所需的 128 位,就像您需要 38 位来存储 IPv4 地址而不是所需的 32 位一样。

还不算太糟糕,对吧?理论上的 IPv8 有 16 个部分,每个部分的大小都是 32 位?与上述功能等效的函数需要 580 位,而不是正确的数学要求:512 位。虽然今天不是问题,但我只是指出了使用连接每个部分的十进制值表示的 IPv4 地址做任何事情时的错误。它的扩展性绝对可怕。

于 2013-08-17T19:23:35.317 回答