比较C中包含IPv4地址的字符串

时间:2013-08-19 06:23:14

标签: c ipv4

我有两个字符串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 个答案:

答案 0 :(得分:14)

值得一提的是还有inet_aton吗?

您可以找到手册页here,下面是简短描述和简短概要。

这个解决方案适用于大多数POSIX系统,但我确信Windows API中有一些等价物,甚至还有一些抽象包装器。

  

inet_ntoa()在POSIX.1-2001中指定。 ineix_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()函数将以网络字节顺序给出的Internet主机地址in转换为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中的地址按网络字节顺序(big-endian),因此@glglgl指出,您必须使用ntohl,其手册页可用here

      

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

    uint32_t ntohl(uint32_t netlong);
    

答案 1 :(得分: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 !");     
  }

答案 2 :(得分: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;
}

答案 3 :(得分: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。