2013-08-17 5 views
2

Привет, я пытаюсь объединить 4 целых числа в одно целое. Я использовал функцию concatinate здесь:Целые числа Concat 4 в одно целое

https://stackoverflow.com/a/12700533/2016977

Мой код:

unsigned concatenate(unsigned x, unsigned y) { 
    unsigned pow = 10; 
    while(y >= pow) 
     pow *= 10; 
    return x * pow + y;   
} 

void stringtoint(){ 
    struct router *ptr; 
    ptr=start; 

    while(ptr!=NULL){ 
     int a; 
     int b; 
     int c; 
     int d; 

     sscanf(ptr->ip, "%d.%d.%d.%d", &a, &b, &c, &d); 
     int num1 = concatenate(a,b); 
     int num2 = concatenate(c,d); 
     int num3 = concatenate(num1,num2); 
     printf("%d\n",num3); 
     ptr=ptr->next; 
    }; 

} 

Проблема:

Я имею дело с числами IP-адреса, например, 198.32.141.140 я разбивая их до 4 целых и объединить их, чтобы сформировать 19832141140, однако моя функция конкатенации делает математику на большем количестве, как 198.32.141.140 (становится) ->-1642695340 но конкатенации IP, которые являются малые числа, например, 164.78.104.1 будет 164781041 (что является правильным)

Как я могу решить проблему, в основном, я пытаюсь сделать строку IP, например. 198.32.141.140 в целого числа19832141140

+3

Вы не можете, а не 32 бит. Но если у вас есть 64-битные целые числа, то вам нужна рутина, способная обрабатывать случай ведущих нулей (как только у вас это будет довольно просто). Как отмечено ниже, ваше преобразование также неоднозначно. Вместо этого вы можете использовать восьмеричную нотацию, если это применимо, которая будет вписываться в 32 бита в качестве бонуса: 'A: B: C: D -> A * 256^0 + B * 256^1 + C * 256^2 + D * 256^3', или вариант, основанный на конкретизации. – Thomas

+4

Ваша проблема недостаточно определена. 11111 11.1.1.1 или 1.11.1.1 или 1.1.11.1 или 1.1.1.11? – bengoesboom

+0

@Thomas, какие другие подходы я должен использовать, в основном я просто хочу создать int IP из строки, удалив '.' и преобразуя строку в целое. –

ответ

12

предложил свой подход, скорее всего, очень большая ошибка. Как вы различаете 127.0.1.1 от 127.0.0.11?

Гораздо лучше рассматривать IP-адреса как они. А именно, a.b.c.d представляет

a * 256^3 + b * 256^2 + c * 256^1 + d * 256^0 

и сделано таким образом, вы не можете, возможно, столкнетесь с вопросом я только что описал. Кроме того, реализация тривиальна:

unsigned int number; 
number = (a << 24) + (b << 16) + (c << 8) + d 
+0

Я не хочу отличать IP, я просто хочу удалить '.' и превратить строку в целое число, поэтому String' 127.0.0.11' -> INT '1270011' –

+2

@Deepak Tivari: Это ошибка. '127.0.0.11' * уже * представляет целое число, просто не так, как вы описываете. Обозначение 'a.b.c.d' - это просто особый способ представления целого числа, так что его легко записать/запомнить. Если вы хотите преобразовать представление в целое число, преобразуйте его в целое, которое оно фактически представляет. – jason

+0

Решает все проблемы с хранением и неоднозначностью, почти так, как будто это должно было интерпретироваться таким образом ... [О, подождите!] (Http://en.wikipedia.org/wiki/IPv4#Addressing) –

3

Вы можете прочитать строку, а затем использовать inet_aton(). В противном случае вы можете сделать, как говорит Джейсон, но вам нужно проверить, что каждое значение целых чисел находится в пределах 0 ... 255 (эти 4 x 8 бит представляют собой 32-битное целое число, содержащее адрес IPv4). inet_aton() будет поддерживать шестнадцатеричные, десятичные и восьмеричные обозначения IPv4-адресов.

1
/** 
** You DO NOT want to do this usually... 
**/ 
#include <stdint.h> 

uint_fast64_t 
concatIPv4Addr(uint_fast16_t parts[]) 
{ 
    uint_fast64_t n = 0; 

    for (int i = 0; i < 3; ++i) { 
     n += parts[i]; 
     n *= 1000; 
    } 

    return (n += parts[3]); 
} 

Я использовал «быстрые» целые типы для целей скорости, но если у вас есть требование к хранилищу, используйте вместо этого соответствующие «наименее» типы. Конечно, это предполагает, что у вас есть компилятор C99 или компилятор C89 с расширениями. В противном случае вы застряли в примитивных типах, где char может даже быть 32-битным в соответствии со стандартом C. Поскольку я не знаю вашу целевую среду, я не сделал никаких предположений. Не стесняйтесь менять подходящие типы примитивов по своему усмотрению.

Я использовал 16-битовое значение (минимум), потому что 8-разрядное число может представлять только 0-255, а это означает, что если было введено 358 случайно, оно будет интерпретироваться как 102, которое все еще действует. Если у вас есть тип, способный хранить более 8 бит и менее 16 бит, вы, очевидно, можете использовать это, но тип должен иметь возможность хранить более 8 бит.

Это в стороне, вы должны по крайней мере, тип 38-разрядное:

4294967295 (32-bit unsigned max) 
255255255255 (255.255.255.255 converted to the integer you want) 
274877906944 (38-bit unsigned max) 

Функция выше будет конвертировать 127.0.1.1 и 127.0.0.От 11 до 127000001001 и 127000000011, соответственно:

127.0.1.1 -> 
127.000.001.001 -> 
127000001001 

127.0.0.11 -> 
127.000.000.011 -> 
127000000011 

Почему так много нулей? Потому что иначе вы не можете сказать разницу между ними! Как говорили другие, вы можете смутить 127.0.1.1 и 127.0.0.11. Используя вышеприведенную функцию или что-то более подходящее, которое фактически преобразует адрес IPv4 в его реальное десятичное представление, у вас не будет такой проблемы.

Наконец, я не получил подтверждения на IPv4-адресе, переданном функции. Я предполагаю, что вы уже убедитесь, что адрес действителен до вызова каких-либо функций, которые сохраняют или используют IPv4-адрес. Кстати, если вы хотите сделать то же самое для IPv6, вы не можете так легко, потому что для этого потребуется строка или преобразование в десятичное число из каждой из 8 частей, каждая из которых не более 16 бит, что дает 5 десятичных цифр на каждую часть или 40 цифр. Чтобы сохранить это, вам потребуется не менее 133 бит, а не 128 бит, необходимых для адреса IPv6, так же, как вам потребуется 38 бит для хранения адреса IPv4 вместо 32 бит.

Все еще не так уж плохо, не так ли? Как насчет теоретического IPv8, где есть 16 частей, каждый из которых имеет 32-битный размер? Эквивалентная функция для вышеперечисленного потребует 580 бит вместо правильного математического требования: 512 бит. Хотя сегодня это не проблема, я просто указываю на ошибку при выполнении чего-либо с адресом IPv4, представленным объединением десятичных значений каждой части. Это ужасно ужасно.

+0

* Другие сказали: «Не строите мост таким образом, это неправильно», но я покажу вам, как его построить, в любом случае, это плохой ответ. Вот как мы заканчиваем плохо разработанными решениями. Сожалею. – jason

+1

Вы правы в том, что говорите, за исключением того, что это плохой ответ, на мой взгляд. В программировании то, что мы должны делать, и что мы на самом деле делаем, - это совсем другое. Ответ решает проблему, хотя он утверждает, что есть лучший способ. Люди могут свободно реализовывать вещи по своему усмотрению. Мы не должны диктовать то, что другой должен (НЕ) делать с точки зрения дизайна кода, какими бы плохими они ни были. Однако мы можем предлагать альтернативы, и это то, что я сделал, даже предоставляя контрпримеры, чтобы спорить с таким дизайном. –

Смежные вопросы