如何在C语言中将“int”数组转换为IP地址字符串?

3

我有一个int数组,它存储了一个IP地址:

int ipArr[4] = {192,168,1,60}

我需要将上面定义的地址转换为字符串,例如 "192.168.1.60"。我尝试使用 sprintfstrcat 函数,但代码仍然很繁琐。而且处理句点标点非常麻烦。 我的代码如下:
char srcIp[16];
int i=0,index=0;
for(i=0;i<4;i++){
   index+=sprintf(&srcIp[index],"%d",sourceIpInt[i]);
   if(i<3){
      index+=sprintf(&srcIp[index],"%c",'.');
    }
}

有人能提供更好的方法吗?


2
你可能知道,一个小的示例代码会很有帮助,以便了解你已经尝试过什么。 - NemoMeMeliorEst
3
请展示代码并解释它为何繁琐或棘手。 - UnholySheep
1
在Unix系统上,您可能需要考虑修改您的代码以使用inet_ntoa及其相关函数。您需要将输入格式更改为不同的格式(打包到32位整数中而不是int数组中),但标准化的代码可能更加健壮。 - Nate Eldredge
3
sprintf是实现该功能的方法。是的,由于在C语言中处理字符串很麻烦,因此代码可能会很冗长。要适应这种情况。 - Lee Daniel Crocker
2
@LeeDanielCrocker 我认为,当代码编写得正确时,理解它不会有任何问题。 - Kamila Szewczyk
显示剩余3条评论
2个回答

2

使用单个sprintf()函数一次性格式化所有IP地址八位字节比在循环中逐个格式化更简单易用。

如果缓冲区可以是本地变量。

char buffer[16];
const int ip[4] = {172,0,0,1};

sprintf(buffer, "%d.%d.%d.%d", *ip, ip[1], ip[2], ip[3]);
printf("IP address is: %s", buffer);

如果您需要使用动态内存,可以执行以下操作。

或者,您可以像下面这样做。

最初的回答:

char * buffer = malloc(16);
const int ip[4] = {172,0,0,1};

if(!buffer) {
    perror("malloc");
    exit(1);
}

sprintf(buffer, "%d.%d.%d.%d", *ip, ip[1], ip[2], ip[3]);
printf("IP address is: %s", buffer);

free(buffer);

在上面的代码中,我使用了动态内存分配来创建缓冲区,并使用sprintf将数据写入其中。
请注意malloc(16)-sizeof(char)按定义等于1,因此我们不需要编写malloc(sizeof(char)* 16)

2
@user3386109:sizeof(char) 在将之前使用 char 的代码更改为 wchar_tint 等其他类型时非常有优势,因为进行更改的人可以搜索出现 char 的位置并决定是否需要更改。他们无法轻易地搜索出现 1 的位置,特别是如果即使在编写 malloc(16 * 1) 后已将其删除。不使用“魔术数字”的规则适用:您不应该在从 foo 转换为 bar 的代码中写入 12。1 是基本数字并不意味着它是... - Eric Postpischil
2
代码中不应该出现 sizeof(char) 这样的“魔法数字”。编写代码的一部分是为了向读者表达含义,而 sizeof(char) 向读者表明程序员正在为 char 对象分配空间。如果代码只是说 malloc(16),仅从这个信息就无法确定它是否缺少 * sizeof(int)。但如果它说 malloc(16 * sizeof(char)),你就可以看到意图。 - Eric Postpischil
@EricPostpischil,你有现实生活中的例子吗?为什么我们要将IP字符串存储在intfloat数组中呢? - Kamila Szewczyk
@KrzysztofSzewczyk:那不相关。 - Eric Postpischil
我只是在问,这里没有真正使用浮点或整数数据类型来存储IP字符串,也许我漏掉了什么...? - Kamila Szewczyk
显示剩余16条评论

-2

更好的方法是使用可移植的库函数!

这将会:

  • 通过添加对IPv6的支持,使您的代码具有未来的可扩展性
  • 使您的代码与许多其他使用IP地址的函数兼容。

例如:

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

void main(){
  // IP addresses might be longer on this system eg. see https://dev59.com/r7Pma4cB1Zd3GeqPtZ-7
  char str[INET_ADDRSTRLEN];

  // this "socket address" is a very portable address format which you will use when dealing with sockets
  struct sockaddr_in sa;

  // this format is not portable or usable when dealing with other libaries, unless you convert it
  // note that technically 'unsigned char' is more accurate, but it will be processed slower than int on modern PC's
  unsigned char a_ipv4addr[4] = {192,168,1,60};

  // Don't do this! This will only work on little-endian machines, when compiled without certain optimizations - so it's not portable. That's why you should rather use the functions - some day soon you might want your code to run on a RISC V processor...
  memcpy(&sa.sin_addr.s_addr,&a_ipv4addr,4);
  inet_ntop(AF_INET, &sa.sin_addr, str, INET_ADDRSTRLEN);
  printf("Bad example with memcpy: %s\n", str); 

  // sprintf your address, and then convert it - if you absolutely have to use your format
  sprintf(str,"%i.%i.%i.%i",a_ipv4addr[0],a_ipv4addr[1],a_ipv4addr[2],a_ipv4addr[3]);
  inet_pton(AF_INET, str, &(sa.sin_addr)); // now you can use it in other functions
  inet_ntop(AF_INET, &sa.sin_addr, str, INET_ADDRSTRLEN); // just to show that it's correct
  printf("Better example from generated string: %s\n", str); 

  // you can also represent it as an unsigned int
  unsigned int ipv4addr=0x3c01a8c0; // c0.a8.01.3c = 192.168.1.60 backwards aka little-endian
  sa.sin_addr.s_addr=ipv4addr;
  inet_ntop(AF_INET, &sa.sin_addr, str, INET_ADDRSTRLEN);
  printf("Example from unsigned int: %s\n", str);

  // you can also represent it as an unsigned int, in decimal
  ipv4addr=192+(168<<8)+(1<<16)+(60<<24);
  sa.sin_addr.s_addr=ipv4addr;
  inet_ntop(AF_INET, &sa.sin_addr, str, INET_ADDRSTRLEN);
  printf("Example from unsigned int decimal example: %s\n", str);

  // Or just store it as a string to begin with...
  inet_pton(AF_INET, "9.9.9.9", &(sa.sin_addr));
  // or if you read it from another function, you can convert it back and print it
  inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN);
  printf("Example from string: %s\n", str); // prints "9.9.9.9"

}

如果您使用的是Linux系统,请尝试以下命令:
man inet_addr

了解更多!


它们不是无处不在吗 - 这难道不就是它:https://github.com/hwoarang/uClibc/blob/master-metag/libc/inet/addr.c? - dagelf
另外,我不知道IP.ToString...太好了!但它是否与他的数组格式兼容? - dagelf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接