Unix Programming - newbie unix/ prog. question

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > March 2006 > newbie unix/ prog. question





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author newbie unix/ prog. question
ptk

2006-03-19, 12:02 pm

Hi Everybody,

I am going through a book on unix network programming and I ran to the
following:


int x2;
struct hostent *hp;
.....
for (x2 = 0; x2 < (int)hp->h_aliases[x2]; ++x2) {
if (x2) {
printf (" %s", hp->h_aliases[x2]);
}
}


This does exatly as the author claimed, namely, if there are aliases it
prints out each alias.

from netdb.h:


/*
* Structures returned by network data base library. All addresses are
* supplied in host order, and returned in network order (suitable for
* use in system calls).
*/
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses from name server */
#ifndef _POSIX_C_SOURCE
#define h_addr h_addr_list[0] /* address, for backward compatiblity */
#endif /* !_POSIX_C_SOURCE */
};


Finally, my question: WHY/HOW does the above loop work.

Thanks much for any time and thought you might be able to give my question,
ptk


Ulrich Eckhardt

2006-03-19, 12:02 pm

ptk wrote:
[slightly reordered]
> struct hostent {
> char *h_name; /* official name of host */
> char **h_aliases; /* alias list */
> int h_addrtype; /* host address type */
> int h_length; /* length of address */
> char **h_addr_list; /* list of addresses from name server */
> #ifndef _POSIX_C_SOURCE
> #define h_addr h_addr_list[0] /* address, for backward compatiblity */
> #endif /* !_POSIX_C_SOURCE */
> };


> int x2;
> struct hostent *hp;
> ....
> for (x2 = 0; x2 < (int)hp->h_aliases[x2]; ++x2) {
> if (x2) {
> printf (" %s", hp->h_aliases[x2]);
> }
> }
>
>
> This does exatly as the author claimed, namely, if there are aliases it
> prints out each alias.

[...]
> Finally, my question: WHY/HOW does the above loop work.


I'd say it works by accident. You're not being very specific about what you
ask, but I guess you mean the condition in the for-loop. In case it's
anything else, be more specific or ask in a C programming group, there's
no magic in the rest.

However. According to my docs, the h_aliases is an array of char pointers,
terminated by a null pointer. So, the first observation to be made is that
the index is compared to a pointer, which is strange in itself and also
the reason why the author casted the pointer to an int [1]. Anyhow, you
are not likely to find any pointers in that array that are in such a low
range that the index becomes bigger than them, so you could also describe
the array like this:

<large integer>
<large integer>
<large integer>
<zero>

So, since the index x2 is relatively small, comparison against the first
three will always return that it is smaller, so the loop goes on, until it
hits the null pointer.

It might have been unclear, but this is really crappy code, because it
relies on unspecified behaviour. The proper way to iterate over such an
array is this:

// with pointers
for( char const*const* alias = hp->h_aliases;
*alias != NULL;
++alias)
{...}

// with indexing
for( int i=0;
hp->h_aliases[i];
++i)
{...}

Uli

[1] ...which otherwise gives compiler errors and here also serves to
possibly truncate the content. It also demonstrates that instead of
applying a cast, one should first understand why the compiler is issuing a
warning - otherwise it just serves to hide errors.

--
http://www.erlenstar.demon.co.uk/unix/
ptk

2006-03-19, 12:02 pm

On 2006-03-19 05:17:04 -0600, Ulrich Eckhardt <doomster@knuut.de> said:

> ptk wrote:
> [slightly reordered]
>
> [...]
>
> I'd say it works by accident. You're not being very specific about what you
> ask, but I guess you mean the condition in the for-loop. In case it's
> anything else, be more specific or ask in a C programming group, there's
> no magic in the rest.
>
> However. According to my docs, the h_aliases is an array of char pointers,
> terminated by a null pointer. So, the first observation to be made is that
> the index is compared to a pointer, which is strange in itself and also
> the reason why the author casted the pointer to an int [1]. Anyhow, you
> are not likely to find any pointers in that array that are in such a low
> range that the index becomes bigger than them, so you could also describe
> the array like this:
>
> <large integer>
> <large integer>
> <large integer>
> <zero>
>
> So, since the index x2 is relatively small, comparison against the first
> three will always return that it is smaller, so the loop goes on, until it
> hits the null pointer.
>
> It might have been unclear, but this is really crappy code, because it
> relies on unspecified behaviour. The proper way to iterate over such an
> array is this:
>
> // with pointers
> for( char const*const* alias = hp->h_aliases;
> *alias != NULL;
> ++alias)
> {...}
>
> // with indexing
> for( int i=0;
> hp->h_aliases[i];
> ++i)
> {...}
>
> Uli
>
> [1] ...which otherwise gives compiler errors and here also serves to
> possibly truncate the content. It also demonstrates that instead of
> applying a cast, one should first understand why the compiler is issuing a
> warning - otherwise it just serves to hide errors.


Thanks for your reply. You are right -- I was asking about the
indexing. I tried the same thing with the **argv in a standard c style
main and it didn't work. Thus, I wondered if there was something I
missed. For what it's worth he does it again in a another section of
code. I don't see how/why the indexing seems to work for him and not
me. I also printed out the various values and you are right they are
very large. Here's the rest of the code:


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

extern int h_errno;

int main (int argc, char **argv)
{
int x, x2;
struct hostent *hp;

for (x = 1; x < argc; ++x) {
// look up hostname
hp = gethostbyname (argv[x]);
// error check
if (!hp) {
// report lookup failure
fprintf (stderr, "ERROR %d (%s) for lookup of '%s'\n",
h_errno, hstrerror(h_errno), argv[x]);
// continue -- don't exit
continue;
}
// report the findings of a successful lookup
printf ("Host %s :\n", argv[1]);
printf (" Officially:\t%s\n", hp->h_name);
printf (" Aliases:\t");
// loop thru aliases
for (x2 = 0; x2 < (int)hp->h_aliases[x2]; ++x2) {
if (x2) {
printf (" %s", hp->h_aliases[x2]);
}
}
printf ("\n");

printf (" Type:\t\t%s\n",
hp->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6");
if (hp->h_addrtype == AF_INET) {
for (x2 = 0; hp->h_addr_list[x2]; ++x2) {
printf (" Address:\t%s\n",
inet_ntoa(*(struct in_addr *)hp->h_addr_list[x2]));
}
}
printf ("\n");
}

return (EXIT_SUCCESS);
}

ptk

2006-03-21, 3:17 am

On Sun, 19 Mar 2006 12:17:04 +0100
Ulrich Eckhardt <doomster@knuut.de> wrote:

> ptk wrote:

[snip]
> However. According to my docs, the h_aliases is an array of char
> pointers, terminated by a null pointer.

CLANK!!!! Got it - boy do I feel dumb.
> So, the first observation to
> be made is that the index is compared to a pointer, which is strange
> in itself and also the reason why the author casted the pointer to an
> int [1]. Anyhow, you are not likely to find any pointers in that
> array that are in such a low range that the index becomes bigger than
> them, so you could also describe the array like this:
>
> <large integer>
> <large integer>
> <large integer>
> <zero>
>
> So, since the index x2 is relatively small, comparison against the
> first three will always return that it is smaller, so the loop goes
> on, until it hits the null pointer.
>
> It might have been unclear, but this is really crappy code,

Thanks, I was really baffled. It's nice to be reassured by a better man
than my self.
> because it
> relies on unspecified behaviour.

^^^^^^^^^^^^^^^^^^^^^
This is a major point being made by Uli

>The proper way to iterate over such
> an array is this:
>
> // with pointers
> for( char const*const* alias = hp->h_aliases;
> *alias != NULL;
> ++alias)
> {...}

[snip]
Thnaks a bunch Uli -- your critique and advice was invaluable, not to
mention your patience.

Regards,
ptk
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com