我有两个字符串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位中,由于上限,我无法将数字存储为整数。
因此我别无选择,只能将整数作为字符串进行比较。
答案 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。