在C中将IP地址字符串转换为整数

uinbv5nw  于 2023-06-28  发布在  其他
关注(0)|答案(5)|浏览(132)

我之前发布了如何实现一个将整数转换为IP地址字符串的函数。那么我们如何反过来呢,也就是说,给定一个字符串(154.111.23.23)是一个地址,我们如何才能得到这个整数,而不使用inet函数。

j7dteeu8

j7dteeu81#

将字符串扫描成四个字节,并将它们相加/移位成32位整数。

dfddblmv

dfddblmv2#

Posix.1-2001为此任务提供了inet_pton()。这也有几个ms-windows版本。

nfg76nw0

nfg76nw03#

//No checking of the input    
unsigned int c1,c2,c3,c4;
scanf("%d.%d.%d.%d",&c1,&c2,&c3,&c4);
unsigned long ip = (unsigned long)c4+c3*256+c2*256*256+c1*256*256*256;
printf("The unsigned long integer is %lu\n",ip);

**编辑:**对于那些对生成的代码感兴趣的人,GCC足够聪明,可以用左移来代替我的256乘法。(在我的程序中,我也称之为exit):

0x80483d4   <main>:     lea    0x4(%esp),%ecx
0x80483d8   <main+4>:       and    $0xfffffff0,%esp
0x80483db   <main+7>:       pushl  -0x4(%ecx)
0x80483de   <main+10>:      push   %ebp
0x80483df   <main+11>:      mov    %esp,%ebp
0x80483e1   <main+13>:      push   %ecx
0x80483e2   <main+14>:      sub    $0x34,%esp
0x80483e5   <main+17>:      lea    -0x14(%ebp),%eax
0x80483e8   <main+20>:      mov    %eax,0x10(%esp)
0x80483ec   <main+24>:      lea    -0x10(%ebp),%eax
0x80483ef   <main+27>:      mov    %eax,0xc(%esp)
0x80483f3   <main+31>:      lea    -0xc(%ebp),%eax
0x80483f6   <main+34>:      mov    %eax,0x8(%esp)
0x80483fa   <main+38>:      lea    -0x8(%ebp),%eax
0x80483fd   <main+41>:      mov    %eax,0x4(%esp)
0x8048401   <main+45>:      movl   $0x8048520,(%esp)
0x8048408   <main+52>:      call   0x8048320 <scanf@plt>
0x804840d   <main+57>:      mov    -0x8(%ebp),%eax
0x8048410   <main+60>:      mov    %eax,%edx
0x8048412   <main+62>:      shl    $0x8,%edx
    0x8048415   <main+65>:      mov    -0xc(%ebp),%eax
0x8048418   <main+68>:      lea    (%edx,%eax,1),%eax
0x804841b   <main+71>:      mov    %eax,%edx
0x804841d   <main+73>:      shl    $0x8,%edx
0x8048420   <main+76>:      mov    -0x10(%ebp),%eax
0x8048423   <main+79>:      lea    (%edx,%eax,1),%eax
0x8048426   <main+82>:      mov    %eax,%edx
0x8048428   <main+84>:      shl    $0x8,%edx
0x804842b   <main+87>:      mov    -0x14(%ebp),%eax
0x804842e   <main+90>:      lea    (%edx,%eax,1),%eax
0x8048431   <main+93>:      mov    %eax,-0x18(%ebp)
0x8048434   <main+96>:      mov    -0x18(%ebp),%eax
0x8048437   <main+99>:      mov    %eax,0x4(%esp)
0x804843b   <main+103>:     movl   $0x804852c,(%esp)
0x8048442   <main+110>:     call   0x8048330 <printf@plt>
0x8048447   <main+115>:     movl   $0x0,(%esp)
0x804844e   <main+122>:     call   0x8048340 <exit@plt>
wlp8pajw

wlp8pajw4#

uint32_t getDecimalValueOfIPV4_String(const char* ipAddress)
{
    uint8_t ipbytes[4]={};
    int i =0;
    int8_t j=3;
    while (ipAddress+i && i<strlen(ipAddress))
    {
       char digit = ipAddress[i];
       if (isdigit(digit) == 0 && digit!='.'){
           return 0;
       }
        j=digit=='.'?j-1:j;
       ipbytes[j]= ipbytes[j]*10 + atoi(&digit);

        i++;
    }

    uint32_t a = ipbytes[0];
    uint32_t b =  ( uint32_t)ipbytes[1] << 8;
    uint32_t c =  ( uint32_t)ipbytes[2] << 16;
    uint32_t d =  ( uint32_t)ipbytes[3] << 24;
    return a+b+c+d;
}
brqmpdu1

brqmpdu15#

inet_pton()最小可运行示例

提及地点:https://stackoverflow.com/a/34077884/895245,但这里有一个改编自man inet_pton的例子:
pton.c

#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    struct in_addr addr;
    int s;

    if (argc != 2) {
        exit(EXIT_FAILURE);
    }
    s = inet_pton(AF_INET, argv[1], &addr);
    if (s <= 0) {
        if (s == 0)
            fprintf(stderr, "Not in presentation format");
        else
            perror("inet_pton");
        exit(EXIT_FAILURE);
    }
    printf("0x%08x\n", ntohl(addr.s_addr));
    exit(EXIT_SUCCESS);
}

编译:

gcc -o pton.out pton.c

运行:

./pton.out 192.187.1.42

输出:

0xc0bb012a

因此,我们看到字符串被转换为整数,例如:

  • 0xc0 = 192
  • 0xbb = 187
  • 0x01 = 1
  • 0x2a = 42

来自man inet_pton的相关报价比较不同选项:
与inet_aton(3)和inet_addr(3)不同,inet_pton()支持IPv6地址。另一方面,inet_pton()只接受点十进制表示法的IPv4地址,而in‐ et_aton(3)和inet_addr(3)允许更通用的数字和点表示法(十六进制和八进制数字格式,以及不需要显式写入所有四个字节的格式)。有关以数字和点表示法处理IPv6地址和IPv4地址的接口,请参见getaddrinfo(3)。
在Ubuntu 23.04上测试。

相关问题