Help for a simple program!

A

awasthi.ashish

Hi friends,

I am writing a simple program to convert an IP address from a
hexadecimal form to dotted-notation form. However, for some reason I am
having problem getting it to work.Here it is:



/* print an ip address, given a hexadecimal number in host byte order
*/
char *get_ip (unsigned int *number)
{
u_int8_t ip1, ip2, ip3, ip4, ip5, ip6;

char *address;


ip1 = (u_int8_t) (*number );
ip2 = (u_int8_t) (*( number + 1 ));
ip3 = (u_int8_t) (*( number + 2 ));
ip4 = (u_int8_t) (*( number + 3 ));

/*change the order of ip1, ip2, etc. because the host is a
little-endian machine */

asprintf(&address, "%u . %u . %u . %u", ip4, ip3, ip2, ip1);

return address;
}


int main()
{
unsigned int temp =0xD8736CF5; /* equivalent to 3631443187 or
216.115.108.245 */

printf("\n %s \n", get_ip(&temp));

return 0;
}


Somehow, when I run this code, I always get the last quartet right
(i.e. 245, which is also the first byte in a little endian machine);
but the remaining bytes are incorrect, and vary on different runs. A
few results I have gotten are: 1.154.168.245, 1.194.188.245,
1.244.198.245.

I tried it for different IP addresses. Always I get the last byte ( of
IP address) right, but the remaining are incorrect.

I suppose I am missing something very simple, but I cannot find it. Can
anybody help please?

Thanks!
 
A

awasthi.ashish

Btw, I ran this program on
* gcc version 2.95.4 20020320 [FreeBSD]
* gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-53)
and
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-54)

All three machines had an Intel CPU.
 
I

Ian Collins

Hi friends,

I am writing a simple program to convert an IP address from a
hexadecimal form to dotted-notation form. However, for some reason I am
having problem getting it to work.Here it is:



/* print an ip address, given a hexadecimal number in host byte order
*/
char *get_ip (unsigned int *number)
{
u_int8_t ip1, ip2, ip3, ip4, ip5, ip6;
prefer standard types, ie. uint8_t.
char *address;
You don't assign anything to address!
ip1 = (u_int8_t) (*number );
ip2 = (u_int8_t) (*( number + 1 ));
ip3 = (u_int8_t) (*( number + 2 ));
ip4 = (u_int8_t) (*( number + 3 ));
number is a pointer to unsigned int, so adding one to it adds
sizeof(unsigned int), which isn't what you intended. try

const uint8_t* p = (uint8_t*)number;

then use p rather than number.

This isn't portable on a big-endian machine, you are better off using
shifts.
/*change the order of ip1, ip2, etc. because the host is a
little-endian machine */

asprintf(&address, "%u . %u . %u . %u", ip4, ip3, ip2, ip1);
What's asprintf?
return address;
}


int main()
{
unsigned int temp =0xD8736CF5; /* equivalent to 3631443187 or
216.115.108.245 */

printf("\n %s \n", get_ip(&temp));

return 0;
}


Somehow, when I run this code, I always get the last quartet right
(i.e. 245, which is also the first byte in a little endian machine);
but the remaining bytes are incorrect, and vary on different runs. A
few results I have gotten are: 1.154.168.245, 1.194.188.245,
1.244.198.245.
You must have ignored quite a few compiler warnings and I'm surprised it
even ran...
 
A

awasthi.ashish

Hey Ian

thanks for pointing out the error. (which was incrementing pointer to
unsigned int rather than in single byte steps).. I don't know how could
have I made this error.. maybe an after-effect of programming beyond 3
am?

Ian said:
You don't assign anything to address!

Yes. Please see explanation on asprintf below.
number is a pointer to unsigned int, so adding one to it adds
sizeof(unsigned int), which isn't what you intended. try

const uint8_t* p = (uint8_t*)number;

then use p rather than number.

worked like a charm. thanks again!
This isn't portable on a big-endian machine, you are better off using
shifts.

Could you explain this a little more?

What's asprintf?

asprintf is just like sprintf .. it assigns the output of printf to a
char pointer; except that it allocates memory dynamically.. so it is
safer than sprintf.

You must have ignored quite a few compiler warnings and I'm surprised it
even ran...

looks like my compiler suppresses the warnings by default.

Thanks so much!

Ashish
 
I

Ian Collins

Hey Ian

thanks for pointing out the error. (which was incrementing pointer to
unsigned int rather than in single byte steps).. I don't know how could
have I made this error.. maybe an after-effect of programming beyond 3
am?
Never a good idea!
Yes. Please see explanation on asprintf below.




worked like a charm. thanks again!




Could you explain this a little more?
Run your program on a big endian machine and the result will be
245.108.115.216 due to the byte order being reversed.

Try

ip4 = (*number >> 24)&0xff;
ip3 = (*number >> 16)&0xff;
ip2 = (*number >> 8)&0xff;
ip1 = (*number)&0xff;

Which gives the expected result on either.

By the way, why pass number as a pointer?
asprintf is just like sprintf .. it assigns the output of printf to a
char pointer; except that it allocates memory dynamically.. so it is
safer than sprintf.
OK, it's just non-standard.
 
E

ed

What's asprintf?

As awasthi says, it's non-standard, for completeness here's the man page
snippet:

NAME
asprintf, vasprintf - print to allocated string

SYNOPSIS
#define _GNU_SOURCE
#include <stdio.h>

int asprintf(char **strp, const char *fmt, ...);

int vasprintf(char **strp, const char *fmt, va_list ap);

DESCRIPTION
The functions asprintf and vasprintf are analogues of sprintf and
vsprintf, except that they allocate a string large enough to hold the
output including the terminating NUL, and return a pointer to it via the
first parameter. This pointer should be passed to free(3) to release the
allocated storage when it is no longer needed.

RETURN VALUE
When successful, these functions return the number of bytes
printed, just like sprintf(3). If memory allocation wasn't possible, or
some other error occurs, these functions will return -1, and the
contents of strp is undefined.

NOTES
These functions are GNU extensions, not in C or POSIX. They are
also available under *BSD. The FreeBSD implementation sets strp to
NULL on error.

For portability this could be done in a few lines of ones own functions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top