如何在C中将`int`数组转换为IP地址字符串?

时间:2019-05-02 18:35:42

标签: c

我有一个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 个答案:

答案 0 :(得分: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)

答案 1 :(得分:-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://stackoverflow.com/questions/55958327/how-to-convert-an-int-array-to-an-ip-address-string-in-c
  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

了解更多!