3

我有两个字符串ip1 = "192.168.145.123"ip2 = "172.167.234.120".

我可以比较这两个字符串是否相等:

strncmp(ip1,ip2) == 0

但是我怎样才能知道

if (ip1 > ip2) {
    ...
}

我试过的

我可以使用 sscanf:

sscanf(ip1,"%d.%d.%d.%d",&s1,&s2,&s3,&s4) 

并存储数字并进行比较。但是在 32 位中,由于上限,我无法将数字存储为整数。

因此,我别无选择,只能将整数作为字符串进行比较。

4

4 回答 4

14

值得一提的是还有 inet_aton 吗?

你可以在这里找到手册页,下面是一个简短的描述和一个简短的概要。

该解决方案适用于大多数 POSIX 系统,但我确信在 Windows API 中有一些等效的,甚至是一些抽象包装器。

inet_ntoa() 在 POSIX.1-2001 中指定。inet_aton() 未在 POSIX.1-2001 中指定,但在大多数系统上都可用。


Linux 程序员手册

inet_aton() 将 Internet 主机地址 cp 从 IPv4 数字和点表示法转换为二进制形式(按网络字节顺序)并将其存储在 inp 指向的结构中。

概要

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);

例子

下面显示了使用 inet_aton() 和 inet_ntoa() 的示例。以下是一些示例运行:

       $ ./a.out 226.000.000.037      # Last byte is in octal
       226.0.0.31
       $ ./a.out 0x7f.1               # First byte is in hex
       127.0.0.1

程序源

   #define _BSD_SOURCE
   #include <arpa/inet.h>
   #include <stdio.h>
   #include <stdlib.h>

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

       if (argc != 2) {
           fprintf(stderr, "%s <dotted-address>\n", argv[0]);
           exit(EXIT_FAILURE);
       }

       if (inet_aton(argv[1], &addr) == 0) {
           fprintf(stderr, "Invalid address\n");
           exit(EXIT_FAILURE);
       }

       printf("%s\n", inet_ntoa(addr));
       exit(EXIT_SUCCESS);
   }

更多信息

  • 字节排序(@Jonathan Leffler)

    inet_ntoa() 函数in将以网络字节顺序给出的 Internet 主机地址转换为 IPv4 点分十进制表示法的字符串。 inet_aton() 将 Internet 主机地址 cp 从 IPv4 数字和点表示法转换为二进制形式(按网络字节顺序)并将其存储在inp指向的结构中。

  • in_addr(@POW)的结构

    在 inet_ntoa()、inet_makeaddr()、inet_lnaof() 和 inet_netof() 中使用的结构 in_addr 定义为:

       typedef uint32_t in_addr_t;
    
       struct in_addr {
           in_addr_t s_addr;
       };
    
  • 与独立于计算机字节序的地址进行比较地址in_addr是网络字节顺序(大字节序),因此正如@glglgl 所指出的,您必须使用ntohl,其手册页可在此处获得。

    ntohl()函数将无符号整数netlong从网络字节顺序转换为主机字节顺序。

    uint32_t ntohl(uint32_t netlong);
    
于 2013-08-19T19:06:46.840 回答
4

您可以尝试性感的方式,将所有值存储在一个无符号整数中并进行比较。

  const char* ip1 = "192.168.145.123";
  const char* ip2 = "172.167.234.120";

  unsigned char s1, s2, s3, s4;
  unsigned int uip1, uip2;

  sscanf(ip1,"%hhu.%hhu.%hhu.%hhu",&s1,&s2,&s3,&s4);
  uip1 = (s1<<24) | (s2<<16) | (s3<<8) | s4; //store all values in 32bits unsigned int

  sscanf(ip2,"%hhu.%hhu.%hhu.%hhu",&s1,&s2,&s3,&s4);
  uip2 = (s1<<24) | (s2<<16) | (s3<<8) | s4;

  if (uip1 > uip2)
  {
    printf("ip1 greater !");   
  }
  else
  {
    printf("ip2 greater or equal !");     
  }
于 2013-08-19T06:36:27.283 回答
1

这个怎么样 :-

#include<stdio.h>
#include<conio.h>

unsigned int convIP(const char ip[]) {
    unsigned char s1, s2, s3, s4;

    if (sscanf(ip, "%hhu.%hhu.%hhu.%hhu", &s1, &s2, &s3, &s4) != 4)
        return 0;

    /* Create a 32 bit Integer using left shift & bitwise OR
            MSB                                            LSB
            +-----8----+-----8------+-----8-----+----8-----+
            |    s1    |     s2     |    s3     |    s4    |   
            +----------+------------+-----------+----------+
     */
    return  (s1 << 24) | (s2 << 16) | (s3 << 8) | (s4 << 0);

}

int ipComp(const char ip1[], const char ip2[]) {
    unsigned int ip_addr1 = convIP(ip1);
    unsigned int ip_addr2 = convIP(ip2);

    return (ip_addr1 >= ip_addr2);

}


int main()
{

    printf("%d\n",ipComp("192.168.145.123","172.167.234.120") ); //1

    printf("%d\n", ipComp("10.0.0.1","192.168.1.1") );  //0

    printf("%d\n",ipComp("192.168.145.123","192.168.145.123")); //1
}

编辑:根据 H2CO3 的建议:

您通常应该避免使用sscanf,而是可以使用strtol(),如下所示:

unsigned long ip2int(const char *ip)
{
    const char *end = ip + strlen(ip);
    unsigned long n = 0;
    while (ip < end) {
        n <<= 8;
        n |= strtoul(ip, (char **)&ip, 10);
        ip++;
    }

    return n;
}
于 2013-08-19T06:47:43.543 回答
1

一个迂腐的“在接受的答案之后”的答案。 采用错误检查

#include <inttypes.h>
int IPstringToUns32(const char *IPString, uint32_t *IPNumber) {
  uint8_t c[4];  // LSByte in c[0]
  char ch;
  const char * format = "%" SCNu8 ".%" SCNu8 ".%" SCNu8 ".%" SCNu8 "%c";
  if (4 != sscanf(IPString, format, &c[3], &c[2], &c[1], &c[0], &ch)) {
    return 1; // parse error
  }
  *IPNumber = (((uint32_t) c[3]) << 24) | (((uint32_t) c[2]) << 16)
      | (((uint32_t) c[1]) << 8) | ((uint32_t) c[0]);
  return 0;
}

假设可以改为使用uint_fast32_t. 此解决方案允许在数字前使用前导空格。

%c[编辑]在格式末尾添加了经典。感谢@glglgl。

于 2013-08-19T20:51:13.177 回答