2009-11-05 14 views
18

Przygotowuję się do quizu i mam poważne podejrzenie, że mogę zostać poproszony o wdrożenie takiej funkcji. Zasadniczo, biorąc pod uwagę adres IP w notacji sieciowej, jak możemy uzyskać to od 32-bitowej liczby całkowitej do ciągu w notacji dziesiętnej z kropkami (coś w stylu 155.247.182.83) ...? Oczywiście nie możemy też używać żadnych funkcji inet ... Jestem zaskoczony!Integer to IP Address - C

+8

Jeśli pisania kodu - należy użyć inet funct jony - i gdybym podał test, to zawiodę cię na nowo na funkcjonujący testowany kod :) – Mark

+2

@Mark Jeśli jesteś w systemie Windows, nie możesz polegać na funkcjach ineta ... W jakiś sposób udało im się powiązać je z biblioteką winsock tak, że 'inet_ntoa', które ma po prostu zrobić podstawowe bicie twiddling, może zawieść. –

Odpowiedz

56

Oto prosty sposób, aby to zrobić: The (ip >> 8), (ip >> 16) i (ip >> 24) przesuwa 2, 3 i 4 bajty do niższego rzędu bajt, podczas gdy & 0xFF izoluje najmniej znaczący bajt na każdym kroku.

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

Na pierwszym etapie znajduje się domniemana bytes[0] = (ip >> 0) & 0xFF;.

Użyj snprintf(), aby wydrukować ciąg.

+0

Dzięki za paczkę iWerner! –

+0

Więc poczekaj, pozwól, że cię zapytam ... jak mam się wtedy odwrócić? Gdybym miał ciąg, jak mógłbym odzyskać int? –

+0

Aby wrócić z ciągu znaków do int, musisz przeanalizować ciąg znaków. tj. nie jest łatwy sposób na hackowanie bitów. –

5

Podpowiedź: podziel 32-bitową liczbę całkowitą na 4 8-bitowe liczby całkowite i wydrukuj je.

Coś na wzór tego (nie skompilowane, 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

Uh ... To się nie kompiluje, czy brakuje funkcji? A liczba zmian jest zła, wydaje się, że dwie cyfry heksadecymalne to cztery bity. Co więcej, lepiej jest przesunąć najpierw i maskę później, jak iWerner. – unwind

+0

Dlaczego to dostało jakieś głosy? – janm

+0

Tak jak powiedziałem, była to szybka odpowiedź. Naprawiono przesunięcie bitowe. –

5

Innym podejściem:

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

To nie jest przenośne; zależy to od sizeof (unsigned) będącego 4 (jak niektóre inne odpowiedzi) i kolejności bajtów wewnątrz int. – janm

+0

@janm, oczywiście, że nie jest przenośny. Jeśli istnieje potrzeba przenośnego kodu, możemy zdefiniować alternatywne związki IP do obsługi większej liczby architektur procesorów bez modyfikowania * rzeczywistego * kodu. –

+0

Podejścia do przenoszenia bitów są przenośne, nie jest wymagany żaden modyfikujący kod _actual_. Po co wprowadzać grono specjalnych przypadków, w których istnieje krótsza, jaśniejsza, przenośna wersja? Wydajność? Na nowoczesnym kompilatorze byłbym zaskoczony, gdybyś mógł zmierzyć różnicę (chociaż nie sprawdziłem). Prawdopodobnie chcesz% d zamiast% x. – janm

1

To jest to, co chciałbym robić, gdy przeszedł bufor ciąg wypełnić i wiedziałem bufor był wystarczająco duży (długi czyli przynajmniej 16 znaków):

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

To byłoby nieco szybsze niż tworzenie tablicy bajtów jako pierwszej i uważam, że jest bardziej czytelna. Zwykle używam snprintf, ale adresy IP nie mogą być dłuższe niż 16 znaków, w tym kończąca się wartość null.

Alternatywnie, jeśli został poproszony o powrót do funkcji 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

rzeczywiście może korzystania funkcję inet. Przestrzegać.

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

Wyniki gcc main.c -ansi; ./a.out jest

Adres IP to 54.208.202.125

Zauważ, że komentator powiedział, że ten nie działa w systemie Windows .

+14

To jest oczywiście najlepsza odpowiedź. Dlaczego nie ma zielonego kleszcza? Nie trzeba już wymyślać nowych kół. –

+1

Nie pracuję nad Winodowami. Ponieważ autor nie określił platformy, ja osobiście nie podoba mi się ta odpowiedź. – MarcinG

+0

Upewnij się, że funkcja inet_ntoa() ma wątek, jeśli twoja aplikacja jest wielowątkowa. Przynajmniej GNU Libc deklaruje zwrotny wątek bufora ciągów lokalnych. https://sourceware.org/git/?p=glibc.git;f=inet/inet_ntoa.c;h=513d22c75e#l24 –

0

Od ciąg do int iz powrotem

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

% RTK instruuje sscanf do zapoznania się unsigned char wskaźnik; (Reading small int with scanf)


inet_ntoa z 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

Moja alternatywne rozwiązanie z odejmowaniem :)

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 

}