![]() |
| | #1 |
| Registered User Join Date: Sep 2008
Posts: 14
| Question regarding a this C program I am currently looking through a simple C program which basically is a very basic nslookup tool. My question is regarding on how some of the C code in this is working. Here is the pieces of code: Code: /* Bare nslookup utility (w/ minimal error checking) */
#include <stdio.h> /* stderr, stdout */
#include <netdb.h> /* hostent struct, gethostbyname() */
#include <arpa/inet.h> /* inet_ntoa() to format IP address */
#include <netinet/in.h> /* in_addr structure */
int main(int argc, char **argv) {
struct hostent *host; /* host information */
struct in_addr h_addr; /* internet address */
if (argc != 2) {
fprintf(stderr, "USAGE: nslookup <inet_address>\n");
exit(1);
}
if ((host = gethostbyname(argv[1])) == NULL) {
fprintf(stderr, "(mini) nslookup failed on '%s'\n", argv[1]);
exit(1);
}
h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
fprintf(stdout, "%s\n", inet_ntoa(h_addr));
exit(0);
}
Code: struct in_addr {
__u32 s_addr;
};
Code: h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); Which looks like this: Code: 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. */
#define h_addr h_addr_list[0] /* Address, for backward compatibility. */
};
Code: /* Return entry from host data base for host with NAME.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern struct hostent *gethostbyname (__const char *__name);
What does is type is __u32 this is in struct in_addr? So the argv[1] is passed to gethostbyname() funtion which returns a pointer to structure and the address is stored in the h_addr_list[0] and this assigned to h_addr and this is passed to net_ntoa(h_addr) to print the output in correct format. Is this correct understanding? Thanks |
| cnb is offline | |
| | #2 | |
| and the Hat of Guessing Join Date: Nov 2007
Posts: 8,862
| Just like anything else, you have to start at the inside of parentheses and then go out: Code: h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); Cast this pointer into a pointer to unsigned long *. (Same memory address, so nothing happens ... yet.) Follow the pointer to get the value. Since we are now pretending this is an unsigned long *, we get however-many-bytes (I'm guessing 4) and using it as a single number. You'll have to read the header to find the definition of __u32, but just from the name I would bet any amount that it's "unsigned <whatever type is 32-bits on your system>". Quote:
| |
| tabstop is offline | |
| | #3 | |
| Registered User Join Date: Sep 2008
Posts: 14
| Quote:
Thanks for your reply. So the following line i can read it as: Code: h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); So does this mean that h_addr.saddr = pointer or a value which is basically h_addr_list[0]? How can i print to the screen the value of h_addr, i.e what is the format specifier for __u32? I checked this out on my system and it is a unsigned 32 bit int. The inet_ntoa function is defined as follows: Code: char *inet_ntoa(struct in_addr in); The inet_ntoa() function converts the Internet host address in given in network byte order to a string in standard numbers-and-dots notation. The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Thanks for your help | |
| cnb is offline | |
| | #4 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,785
| Sigh. Realize that memory is only raw - it does not have any type information, it's just bits. So information is stored there in bits, and the compiler keeps track of the type ONLY by looking at the type of the variable the data is stored inside. This means that you can tell the compiler to treat the data in another way. That's done via the cast. And it's a pointer to unsigned long, which is then dereferenced to get the data.
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |
| Elysia is offline | |
| | #5 | ||||
| and the Hat of Guessing Join Date: Nov 2007
Posts: 8,862
| Quote:
Quote:
Quote:
Quote:
| ||||
| tabstop is offline | |
| | #6 |
| Registered User Join Date: Sep 2008
Posts: 14
| Hi, Thanks for your help....just one more further clarification Code: h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); http://unixwiz.net/techtips/reading-cdecl.html How do i apply this rule to the above piece of code.....i.e. how do i treat the "->" symbol? So i start by applying the rule to the following piece: Code: (unsigned long *) host Is there any other easy way to extract the value from h_addr_list[0] and assign it to h_addr? Thanks |
| cnb is offline | |
| | #7 | ||
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,785
| Quote:
Code: h_addr.s_addr = *((unsigned long*)host->h_addr_list[0]); This: (unsigned long*) is a cast. It vasts the right expression into the given type you specify. So it converts the expression host->h_addr_list[0] to unsigned long*. Now, host is a pointer to a struct and we want to access one of its members. Therefore we use the -> syntax. It's a shortcut used on pointers since the * operator has lower precedence than the . operator, therefore you must write (*var).something. h_addr_list[0] is of the wrong type to us, so we take its value and cast it to the right type, unsigned long*. Now we want to assign the value it's pointing to, so we must dereference it. It's not difficult, you just have to read up on pointers a bit to get the grasp on the whole. This was already explained to you.
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| ||
| Elysia is offline | |
| | #8 | |
| Registered User Join Date: Sep 2008
Posts: 14
| Quote:
So outer brackets i.e. Code: h_addr.s_addr = *(expression); So the expression is just accessing one of the members from host structure and making sure the type is correct by using cast and this is to match the type of h_addr.s_addr? Thanks | |
| cnb is offline | |
| | #9 | |||
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,785
| Quote:
Quote:
Assign the value pointed to by the host->h_addr_list[0] to h_addr.s_addr. Allocating means reserving memory, ie malloc.
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |||
| Elysia is offline | |
| | #10 | |
| Registered User Join Date: Sep 2008
Posts: 14
| Quote:
Thanks alot for your help.... I have been reading more on the cast operator and in the oreilly book that i have on C programming has a small section which describes the cast operator in C. Now the example given is very simple i.e. it show how to use the cast operator to change between int and long. In the code that we have been discussing so far i.e.: Code: (unsigned long*)host Code: (unsigned long) *host Thanks Last edited by cnb; 10-11-2008 at 04:42 AM. | |
| cnb is offline | |
| | #11 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,785
| Of course it's wrong. They don't do the same thing. Let's just define the type of host to T*, OK? In the second example, first you dereference host, so you get T. Then you cast it to unsigned long. Because it's a cast, the compiler may change the data or truncate the data to fit into unsigned long. In the first example, you cast the address of host, the pointer, to unsigned long. This means the compiler will treat the information stored as unsigned long and then dereference to get an unsigned long. This example clearly outlines the problems you may encounter. Example: Code: double* x = (double*)malloc( sizeof(double) ); //new double;
*x = 1.2345678;
unsigned __int64 y = (unsigned long)*x; // What do you think this will do?
printf("%f\n%f\n", *x, *(double*)&y);
unsigned __int64 z = *(unsigned __int64*)x;
printf("%f\n%f\n", *x, *(double*)&z);
free(x);
1.234568 0.000000 1.234568 1.234568
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
Last edited by Elysia; 10-11-2008 at 05:01 AM. | |
| Elysia is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| newb question: probs with this program | ajguerrero | C Programming | 5 | 04-19-2006 08:04 AM |
| Random Question Assign Program | mikeprogram | C++ Programming | 6 | 11-17-2005 10:04 PM |
| I'm not ask for ENTIRE program, only 1 Question ! | Th3-SeA | C Programming | 10 | 10-01-2003 12:33 PM |
| Question type program for beginners | Kirdra | C++ Programming | 7 | 09-15-2002 05:10 AM |
| N00b Question. Can't get this program to work with me !!! | Halo | C Programming | 8 | 03-26-2002 07:55 AM |