2009-11-05 3 views
18

Je me prépare pour un quiz, et j'ai de fortes raisons de penser que je pourrais être chargé de mettre en place une telle fonction. Fondamentalement, étant donné une adresse IP dans la notation de réseau, comment pouvons-nous obtenir cela à partir d'un entier de 32 bits dans une chaîne dans sa notation décimale à points (quelque chose comme 155.247.182.83) ...? Évidemment, nous ne pouvons pas utiliser n'importe quel type de fonctions inet non plus ... Je suis perplexe!Entier à l'adresse IP - C

+8

Si vous écrivez du code - vous devez utiliser inet funct ions - et si je donnais le test je vous manquerais pour réinventer le code de travail testé :) – Mark

+2

@Mark Si vous êtes sur Windows, vous ne pouvez pas compter sur les fonctions inet ... Ils ont en quelque sorte réussi à les attacher dans la bibliothèque de winsock de sorte que 'inet_ntoa', qui est censé faire juste un peu de base, peut échouer. –

Répondre

56

Voici une méthode simple pour le faire: Le (ip >> 8), (ip >> 16) et (ip >> 24) déplace le 2e, 3e et 4e octets dans l'ordre inférieur octet, tandis que & 0xFF isole l'octet le moins significatif à chaque étape.

void print_ip(int ip) 
{ 
    unsigned char bytes[4]; 
    bytes[0] = ip & 0xFF; 
    bytes[1] = (ip >> 8) & 0xFF; 
    bytes[2] = (ip >> 16) & 0xFF; 
    bytes[3] = (ip >> 24) & 0xFF; 
    printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]);   
} 

Il y a une bytes[0] = (ip >> 0) & 0xFF; implicite à la première étape.

Utilisez snprintf() pour l'imprimer en une chaîne.

+0

Merci beaucoup iWerner! –

+0

Alors attendez, laissez-moi vous demander si ... comment irais-je dans l'autre sens? Si j'avais la chaîne, comment pourrais-je récupérer l'int? –

+0

Pour revenir de la chaîne à l'int, vous devez analyser la chaîne. c'est-à-dire pas de moyen de piratage facile. –

5

Indice: divisez l'entier de 32 bits en 4 entiers de 8 bits et imprimez-les.

Quelque chose le long des lignes de ce (non compilé, YMMV):

int i = 0xDEADBEEF; // some 32-bit integer 
printf("%i.%i.%i.%i", 
      (i >> 24) & 0xFF, 
      (i >> 16) & 0xFF, 
      (i >> 8) & 0xFF, 
      i & 0xFF); 
+3

Euh ... Cela ne compile pas, y at-il un appel de fonction manquant? Et les nombres de décalage sont tous faux, ils semblent penser que deux chiffres hexagonaux sont égaux à quatre bits. En outre, il est préférable de passer d'abord en premier et de masquer plus tard, comme iWerner. – unwind

+0

Pourquoi cela a-t-il eu des votes? – janm

+0

Comme je l'ai dit, c'était une réponse rapide. Correction du décalage de bits. –

5

Une autre approche:

union IP { 
    unsigned int ip; 
    struct { 
     unsigned char d; 
     unsigned char c; 
     unsigned char b; 
     unsigned char a; 
    } ip2; 
}; 

... 
char ips[20]; 
IP ip; 
ip.ip = 0xAABBCCDD; 

sprintf(ips, "%x.%x.%x.%x", ip.ip2.a, ip.ip2.b, ip.ip2.c, ip.ip2.d); 
printf("%s\n", ips); 
+2

Ce n'est pas portable; Cela dépend de sizeof (unsigned) étant 4 (comme d'autres réponses) et l'ordre des octets dans un int. – janm

+0

@janm, bien sûr, ce n'est pas portable. S'il y a un besoin de code portable, nous pouvons définir des unions IP alternatives pour gérer plus d'architectures cpu sans modifier le code * réel *. –

+0

Les approches de déplacement de bits sont portables, aucun code _actual_ de modification n'est requis. Pourquoi introduire une série de cas spéciaux où il existe une version plus courte, plus claire et plus portable? Performance? Sur un compilateur moderne, je serais surpris si vous pouviez mesurer une différence (bien que je n'ai pas vérifié). Et vous voulez probablement% d au lieu de% x. – janm

1

Voilà ce que je ferais si passé un tampon de chaîne pour remplir et je savais que le tampon était assez grande (au moins 16 caractères):

sprintf(buffer, "%d.%d.%d.%d", 
    (ip >> 24) & 0xFF, 
    (ip >> 16) & 0xFF, 
    (ip >> 8) & 0xFF, 
    (ip  ) & 0xFF); 

Ce serait légèrement plus rapide que de créer un tableau d'octets en premier, et je pense qu'il est plus lisible. J'utiliserais normalement snprintf, mais les adresses IP ne peuvent pas contenir plus de 16 caractères, y compris la valeur null.

Alternativement, si on m'a demandé d'une fonction renvoyant un char *:

char* IPAddressToString(int ip) 
{ 
    char[] result = new char[16]; 

    sprintf(result, "%d.%d.%d.%d", 
    (ip >> 24) & 0xFF, 
    (ip >> 16) & 0xFF, 
    (ip >> 8) & 0xFF, 
    (ip  ) & 0xFF); 

    return result; 
} 
1
#include "stdio.h" 

void print_ip(int ip) { 
    unsigned char bytes[4]; 
    int i; 
    for(i=0; i<4; i++) { 
     bytes[i] = (ip >> i*8) & 0xFF; 
    } 
    printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]); 
} 

int main() { 
    int ip = 0xDEADBEEF; 
    print_ip(ip); 
} 
73

En fait, vous pouvez utiliser une fonction iNet. Observer.

main.c:

#include <arpa/inet.h> 

main() { 
    uint32_t ip = 2110443574; 
    struct in_addr ip_addr; 
    ip_addr.s_addr = ip; 
    printf("The IP address is %s\n", inet_ntoa(ip_addr)); 
} 

Les résultats de gcc main.c -ansi; ./a.out est

L'adresse IP est 54.208.202.125

Notez qu'un intervenant a déclaré que cela ne fonctionne pas sous Windows .

+14

C'est évidemment la meilleure réponse. Pourquoi n'a-t-il pas la tique verte? Pas besoin d'aller réinventer les roues. –

+1

Ne fonctionne pas sur Winodows. Puisque l'auteur n'a pas précisé la plate-forme, personnellement, je n'aime pas cette réponse. – MarcinG

+0

Assurez-vous que votre inet_ntoa() est sensible au fil si votre application est multithread. GNU Libc, au moins, déclare le thread de retour de chaîne statique statique local. https://sourceware.org/git/?p=glibc.git;f=inet/inet_ntoa.c;h=513d22c75e#l24 –

0

chaîne à partir int et retour

const char * s_ip = "192.168.0.5"; 
unsigned int ip; 
unsigned char * c_ip = (unsigned char *)&ip; 
sscanf(s_ip, "%hhu.%hhu.%hhu.%hhu", &c_ip[3], &c_ip[2], &c_ip[1], &c_ip[0]); 
printf("%u.%u.%u.%u", ((ip & 0xff000000) >> 24), ((ip & 0x00ff0000) >> 16), ((ip & 0x0000ff00) >> 8), (ip & 0x000000ff)); 

% TSP indique sscanf à lire dans le pointeur unsigned char; (Reading small int with scanf)


inet_ntoa de glibc

char * 
inet_ntoa (struct in_addr in) 
{ 
unsigned char *bytes = (unsigned char *) &in; 
__snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d", 
bytes[0], bytes[1], bytes[2], bytes[3]); 
return buffer; 
} 
1

Ma solution de rechange avec soustraction :)

void convert(unsigned int addr) 
{  
unsigned int num[OCTET], 
      next_addr[OCTET]; 

int bits = 8; 
unsigned int shift_bits; 
int i; 

next_addr[0] = addr; 
shift_bits -= bits; 
num[0] = next_addr[0] >> shift_bits; 

for (i = 0; i < OCTET-1; i ++) 
{  
    next_addr[i + 1] = next_addr[i] - (num[i] << shift_bits); // next subaddr 
    shift_bits -= bits; // next shift 
    num[i + 1] = next_addr[i + 1] >> shift_bits; // octet 
} 

printf("%d.%d.%d.%d\n", num[0], num[1], num[2], num[3]); 
} 
0
void ul2chardec(char*pcIP, unsigned long ulIPN){ 
int i; int k=0; char c0, c1; 
for (i = 0; i<4; i++){ 
    c0 = ((((ulIPN & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8)))/100) + 0x30; 
    if (c0 != '0'){ *(pcIP + k) = c0; k++; } 
    c1 = (((((ulIPN & (0xff << ((3 - i) * 8))) >> ((3 - i) * 8))) % 100)/10) + 0x30; 
    if (!(c1 =='0' && c0=='0')){ *(pcIP + k) = c1; k++; } 
    *(pcIP +k) = (((((ulIPN & (0xff << ((3 - i) * 8)))) >> ((3 - i) * 8))) % 10) + 0x30; 
    k++; 
    if (i<3){ *(pcIP + k) = '.'; k++;} 
} 
*(pcIP + k) = 0; // pcIP should be x10 bytes 

}