2

Hi i am trying to concatinate 4 integers one integer. I used the concatinate function found here :

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

My code:

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

}

The problem:

I am dealing with IP address numbers e.g. 198.32.141.140 i am breaking them down to 4 integers and concatenate them to form 19832141140, however my concatenate function is doing maths on the larger number like 198.32.141.140 (becomes) - >-1642695340 but it is concatenating the IP which are small numbers e.g. 164.78.104.1 becomes 164781041 (which is correct)

How should i solve the problem, basically i am trying to make a string of IP e.g. 198.32.141.140 into an integer number 19832141140

Community
  • 1
  • 1
KAKAK
  • 879
  • 7
  • 16
  • 32
  • 3
    You can't, not in 32 bits. But if you have 64-bit integers, what you need is a routine that is able to handle the case of leading zeroes (once you have that it's pretty simple). As noted below, your conversion is also ambiguous. You can use octal notation instead if applicable, which will fit in 32 bits as a bonus: `A:B:C:D -> A * 256^0 + B * 256^1 + C * 256^2 + D * 256^3`, or a variant based on endianness. – Thomas Aug 17 '13 at 16:37
  • 4
    Your problem is not well defined enough. Is 11111 11.1.1.1 or 1.11.1.1 or 1.1.11.1 or 1.1.1.11? – bengoesboom Aug 17 '13 at 16:38
  • @Thomas what other approaches should i take, basically i just want to create an int of the IP from the string by removing the `.` and converting string to integer. – KAKAK Aug 17 '13 at 16:39
  • @DeepakTivari The point is that you won't be able to go back from that integer to an IP unambiguously, raising questions about how useful your conversion really is. Trying to understand your high-level problem, in other words.. – Thomas Aug 17 '13 at 16:41
  • possible duplicate of [Converting IP from C string to unsigned int?](http://stackoverflow.com/questions/7443846/converting-ip-from-c-string-to-unsigned-int) – alk Aug 17 '13 at 16:42
  • Are you sure you need that? How do you want to deal with IPv6 addresses? (I hope you *will* do so, because we are 2013 and newly written applications should know about that...) – glglgl Aug 17 '13 at 16:44
  • You have a fundamental mathematical problem: `255,255,255,255 > (4,294,967,295 = UINT_MAX)` – recursion.ninja Aug 17 '13 at 16:47
  • 1
    @DeepakTivari If for some reason you really insist on your approach then using `unsigned long long` will give you at least 64 bits results, which should suffice. Just make sure to consistently use this type in the remainder of your code (see `num1`, `num2` and `%d`). – Bryan Olivier Aug 17 '13 at 16:57
  • Besides all those "how-tos": Would the OP mind to explain the use-case behind the question? – alk Aug 17 '13 at 17:10

3 Answers3

12

Your proposed approach is likely a very big mistake. How do you distinguish 127.0.1.1 from 127.0.0.11?

It's much better to treat IP addresses as exactly what they are. Namely, a.b.c.d represents

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

and done in this way you can not possibly run into the issue I just described. Moreover, the implementation is trivial:

unsigned int number;
number = (a << 24) + (b << 16) + (c << 8) + d
jason
  • 236,483
  • 35
  • 423
  • 525
  • I do not want to distinguish the IP, i just want to remove the `.` and turn the string into integer so String `127.0.0.11` --> INT `1270011` – KAKAK Aug 17 '13 at 16:43
  • 2
    @Deepak Tivari: That's a mistake. `127.0.0.11` *already* represents an integer, just not in the way that you describe. The `a.b.c.d` notation is just a very special way of representing the integer so that it's easy to write / remember. If you want to convert the representation to an integer, convert it to the integer that it actually represents. – jason Aug 17 '13 at 16:44
  • Solves all storage & ambiguity problems, almost like it was supposed to be interpreted this way... [Oh wait!](http://en.wikipedia.org/wiki/IPv4#Addressing) – recursion.ninja Aug 17 '13 at 16:50
  • 1
    @Jason May I suggest you use an `unsigned int number`. Getting negative IP addresses may be a bit unexpected. – Bryan Olivier Aug 17 '13 at 16:52
3

You may read a line, and then use inet_aton(). Otherwise, you can do as Jason says, but you'd need to check each integers value to be within 0 ... 255 (those 4 x 8 bits represent the 32bit integer containing an IPv4 address). inet_aton() would support hex, dec and octal notation of IPv4 addresses.

Community
  • 1
  • 1
Sam
  • 7,778
  • 1
  • 23
  • 49
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]);
}

I used the "fast" integer types for speed purposes, but if you have a storage requirement, use the corresponding "least" types instead. Of course this assumes you have a C99 compiler or a C89 compiler with extensions. Otherwise you're stuck with the primitive types where a char could even be 32-bit according to the C standard. Since I don't know your target environment, I made no assumptions. Feel free to change to the appropriate primitive types as you see fit.

I used a 16-bit value (minimum) because an 8-bit number can only represent 0-255, meaning if 358 was entered accidentally, it would be interpreted as 102, which is still valid. If you have a type able to store more than 8 bits and less than 16 bits, you can obviously use that, but the type must be able to store more than 8 bits.

That aside, you will need at least a 38-bit type:

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

The function above will convert 127.0.1.1 and 127.0.0.11 to 127000001001 and 127000000011 respectively:

127.0.1.1 ->
127.000.001.001 ->
127000001001

127.0.0.11 ->
127.000.000.011 ->
127000000011

Why so many zeros? Because otherwise you can't tell the difference between them! As others have said, you could confuse 127.0.1.1 and 127.0.0.11. Using the function above or something more appropriate that actually converts an IPv4 address to its real decimal representation, you won't have such a problem.

Lastly, I did no validation on the IPv4 address passed to the function. I assume you already ensure the address is valid before calling any functions that save or use the IPv4 address. BTW, if you wanted to do this same thing for IPv6, you can't so easily because that would require a string or conversion to decimal of each of the 8 parts, each of which is at most 16-bit, yielding 5 decimal digits per part, or 40 digits. To store that, you'd need a minimum of 133 bits, rather than the 128 bits required for the IPv6 address, just as you'd need 38 bits to store an IPv4 address instead of the 32 bits required.

Still not too bad, right? How about a theoretical IPv8 where there are 16 parts, each of which are 32-bit in size? The equivalent function to the one above would require 580 bits, instead of the proper mathematical requirement: 512 bits. While not a problem today, I'm simply pointing out the error in doing anything with an IPv4 address represented by concatenating the decimal values of each part. It scales absolutely terribly.

  • *Others said "don't build a bridge this way, it is wrong" but I'm going to show you how to build it anyway* is a bad answer. This is how we end up with poorly-engineered solutions. Sorry. – jason Aug 17 '13 at 21:51
  • 2
    You're right in what you say, except for it being a bad answer in my opinion. In programming, what we ought to do and what we actually do are very different things. The answer solves the problem, though it does state that there is a better way. People are free to implement things as they want. We are not the ones to dictate what another must (NOT) do in terms of code design, no matter how poor it may be. We are free to suggest alternatives however, and that is what I did, even providing counterexamples to argue against such a design. –  Aug 17 '13 at 22:28