I have two strings ip1 = "192.168.145.123" and ip2 = "172.167.234.120".

I can compare these two strings for equality:

strncmp(ip1,ip2) == 0

However how can I find out

if (ip1 > ip2) {
    ...
}

What I have tried

I can use sscanf:

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

and store the numbers and compare. However in 32 bit I can't store the numbers as integers due to the upper limit.

Thus I have no choice but to compare the integers as strings.

有帮助吗?

解决方案 2

You can try the sexy way, store all values in one unsigned integer and compare it.

  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 !");     
  }

其他提示

Is it worth mentionning that there is also inet_aton ?

You can find the man page here, below is a short description and a short synopsis.

This solution will work on most POSIX systems, but I'm sure there is some equivalent in the Windows APIs, and even some abstraction wrapper.

inet_ntoa() is specified in POSIX.1-2001. inet_aton() is not specified in POSIX.1-2001, but is available on most systems.


Linux Programmer's Manual

inet_aton() converts the Internet host address cp from the IPv4 numbers-and-dots notation into binary form (in network byte order) and stores it in the structure that inp points to.

SYNOPSIS

#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);

EXAMPLE

An example of the use of inet_aton() and inet_ntoa() is shown below. Here are some example runs:

       $ ./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

Program source

   #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);
   }

Further informations

  • Byte ordering (@Jonathan Leffler)

    The inet_ntoa() function converts the Internet host address in, given in network byte order, to a string in IPv4 dotted-decimal notation. inet_aton() converts the Internet host address cp from the IPv4 numbers-and-dots notation into binary form (in network byte order) and stores it in the structure that inp points to.

  • Structure of in_addr (@POW)

    The structure in_addr as used in inet_ntoa(), inet_makeaddr(), inet_lnaof() and inet_netof() is defined in as:

       typedef uint32_t in_addr_t;
    
       struct in_addr {
           in_addr_t s_addr;
       };
    
  • Compare to address independently of computer-endianness Addresses in in_addr are in network byte order (big-endian), so as pointed by @glglgl, you have to use ntohl, whose man page is available here.

    The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.

    uint32_t ntohl(uint32_t netlong);
    

How about this :-

#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
}

Edit: As suggested by H2CO3:

You should generally avoid using sscanf, instead you can use strtol(), like this:

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;
}

A pedantic "after the accepted answer" answer. Error checking employed.

#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;
}

Suppose one could instead use uint_fast32_t. This solution allows for leading white space before digits.

[Edit] Added classic %c at the end of the format. Thanks to @glglgl.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top