2009-11-05 23 views
18

Me estoy preparando para una prueba, y tengo una fuerte sospecha de que podría tener la tarea de implementar dicha función. Básicamente, dada una dirección IP en notación de red, ¿cómo podemos obtener eso de un entero de 32 bits en una cadena en su notación decimal con puntos (algo así como 155.247.182.83) ...? Obviamente tampoco podemos usar ningún tipo de función inet ... ¡Estoy perplejo!Entero a la dirección IP - C

+8

Si está escribiendo código - que debe utilizar inet funct iones - y si diera la prueba, te fallaría si reinventaras el código de prueba de trabajo :) – Mark

+2

@Mark Si estás en Windows no puedes confiar en las funciones de entrada ... De alguna manera lograron vincularlas a la biblioteca winsock de modo que 'inet_ntoa', que se supone que solo hace un twiddling básico, puede fallar. –

Respuesta

56

He aquí un método simple de hacerlo: La (ip >> 8), (ip >> 16) y (ip >> 24) mueve el segundo, bytes 3 y 4 en el orden inferior byte, mientras que & 0xFF aísla el byte menos significativo en cada paso.

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

Hay un implícita bytes[0] = (ip >> 0) & 0xFF; en el primer paso.

Use snprintf() para imprimirlo en una cadena.

+0

¡Gracias a iWerner! –

+0

Así que espere, déjeme preguntarle piensa ... ¿cómo iría al revés entonces? Si tuviera el hilo, ¿cómo podría recuperar el int? –

+0

Para regresar de la cadena al int, necesitaría analizar la cadena. es decir, no es una manera fácil de hackear bit. –

5

Sugerencia: divide el entero de 32 bits en 4 enteros de 8 bits e imprímalo.

Algo a lo largo de las líneas de este (no compilado, tu caso es distinto):

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

Uh ... Esto no se compila, ¿falta una llamada a la función? Y los recuentos de turnos están mal, parecen pensar que dos dígitos hexadecimales equivalen a cuatro bits. Además, es mejor cambiar primero y luego enmascarar, como iWerner. – unwind

+0

¿Por qué esto obtuvo votos? – janm

+0

Como dije, fue una respuesta rápida. Se corrigió el cambio de bit. –

5

Otro enfoque:

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

Esto no es portátil; depende de que sizeof (unsigned) sea 4 (como algunas otras respuestas) y el orden de bytes dentro de un int. – janm

+0

@janm, por supuesto que no es portátil. Si existe la necesidad de un código portátil, podemos definir uniones de IP alternativas para manejar más arquitecturas de CPU sin modificar el código * real *. –

+0

Los enfoques de cambio de bit son portátiles, no es necesario modificar el código _actual_. ¿Por qué introducir un montón de casos especiales donde hay una versión más corta, más clara y portátil? ¿Actuación? En un compilador moderno, me sorprendería si pudiera medir una diferencia (aunque no lo he comprobado). Y probablemente desee% d en vez de% x. – janm

1

Esto es lo que haría si se aprueba un búfer de cadena para llenar y yo sabía que el tampón era lo suficientemente grande (es decir, al menos 16 caracteres de longitud):

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

Esto sería un poco más rápido que crear una matriz de bytes primero, y creo que es más legible. Normalmente usaría snprintf, pero las direcciones IP no pueden tener más de 16 caracteres, incluido el nulo de terminación.

Alternativamente, si se me pidió para una función que devuelve 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 realidad puede utilizar una función de inet. Observar.

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

Los resultados de gcc main.c -ansi; ./a.out es

La dirección IP es 54.208.202.125

Tenga en cuenta que un comentarista dijo que esto no funciona en Windows .

+14

Esta es obviamente la mejor respuesta. ¿Por qué no tiene el tic verde? No hay necesidad de volver a inventar ruedas. –

+1

No funcionará en Winodows. Como el autor no especificó la plataforma, personalmente no me gusta esta respuesta. – MarcinG

+0

Asegúrate de que tu inet_ntoa() tenga en cuenta el subproceso si tu aplicación tiene varios subprocesos. GNU Libc, al menos, declara que el hilo de la memoria tampón de cadenas estáticas retorna local. https://sourceware.org/git/?p=glibc.git;f=inet/inet_ntoa.c;h=513d22c75e#l24 –

0

de String a int y la espalda

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

% hhu sscanf instruye para leer en puntero char sin signo; (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

Mi solución alternativa con la resta :)

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 

}