Typecasting Structures?

T

tweak

I'm struggling with the concept of typecasting when
setting up a TCP client.

Here's a code snip (modified from W. Richard Stevens Unix Programming
book) to demonstrate where I am struggling:

int sockfd;
struct sockaddr_in servaddr;

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* PORT 13 */

/* argv[1] = "127.0.0.1" */

if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr)) <= 0 ) {
perror("inet_pton()");
exit(1);
}

if ( (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) <
0) {
perror("connect()");
exit(1);
}

When this line occurs:

(struct sockaddr *) &servaddr

the previously assigned values within servaddr are typecast to struct
sockaddr,
which is defined as:

struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};

My confusion is how sa_data[14] becomes populated. I do not
understand the conversion.

Can anyone help me out?

I stepped through the code creating a pointer of type struct sockaddr
and pointed it to the address of servaddr. But I do not understand
why sa_data[14] would have data looking like \111\0\r\0\0 . . .
nor do I understand how to convert that string back to it's original
form.

Any help would be appreciated.

Thanks,

Brian

P.S. I'm compiling using gcc, and debuggin with gdb.
 
D

Dan Pop

In said:
When this line occurs:

(struct sockaddr *) &servaddr

the previously assigned values within servaddr are typecast to struct
sockaddr,

Nonsense! This is a *pointer* cast that has no effect on the values of
the members of servaddr. To understand the effect, you have to
compare the definitions of the two structures.

IIRC, reading the book provides all the enlightenment. Don't play with
the examples *without* reading *all* the relevant text.

Dan
 
T

tweak

Dan said:
Nonsense! This is a *pointer* cast that has no effect on the values of
the members of servaddr. To understand the effect, you have to
compare the definitions of the two structures.

IIRC, reading the book provides all the enlightenment. Don't play with
the examples *without* reading *all* the relevant text.

Dan

I understand the text just fine. It's when I assign the pointer to
another pointer of the type being cast to and look at the dereferenced
values that I get confused.

If I declare the structure

struct sockaddr_in servaddr

and I put in

servaddr.sin_family = AF_INET; /* which corresponds to a value */

and I put in

servaddr.sin_port = htons(13) /* which converts port 13 and assigns it
to sin_port */

and I place a value in sin_addr. According to my debugger, my structure
looks like:

servaddr = {sin_family =2, sin_port = 3328, sin_addr = {s_addr =
16777343}, sin_zero = "\0\0\0\0\0\0\0"}

Now, for the connect() function, I am passing a pointer and typecasting
it. I'm okay with that.

If I want to see what the values change to during that typecast, I
create a structure of the type being cast to as follows:

struct sockaddr *test;

I then make the assignment:

test = (struct sockaddr *) &servaddr

now, in my debugger, I just ask to display the deference to that pointer
*test, and I get:

*test = {sa_family = 2, sa_data = "\0\r\177\0\0\001\0\0\0\0\0\0\0"}

I do not understand why sa_data is converted to that string.

I hope that clarifies. I am okay with setting up clients and servers;
I'm just stuck on how C is working above.

Cheers,

Brian
 
S

Stephen Sprunk

tweak said:
I understand the text just fine. It's when I assign the pointer to
another pointer of the type being cast to and look at the dereferenced
values that I get confused. ....
servaddr = {sin_family =2, sin_port = 3328, sin_addr = {s_addr =
16777343}, sin_zero = "\0\0\0\0\0\0\0"} ....
*test = {sa_family = 2, sa_data = "\0\r\177\0\0\001\0\0\0\0\0\0\0"}

I do not understand why sa_data is converted to that string.

It isn't "converted" to that string. That is your machine's representation
of the sin_port, sin_addr, and sin_zero fields in your sockaddr_in.

sin_port = 3328 = 0x0D00
sin_addr = 16777343 = 0x0100007f
sin_zero = 0x00000000000000

Once you adjust for your machine being little endian, you get:

sa_data = 0x000D7F00000100000000000000

Casting one pointer type to another merely causes the compiler to interpret
the object pointed to in a different manner -- it doesn't change what's
actually there.

S
 
J

Jack Klein

in comp.lang.c:

First your title displays a fundamental misunderstanding that is
augmenting your confusion.

You _are not_ casting structures, and you _cannot_ cast structures in
C.

You can cast a pointer to any type of object to a pointer to any other
type of object at all, and that is what you are doing here.
I understand the text just fine. It's when I assign the pointer to
another pointer of the type being cast to and look at the dereferenced
values that I get confused.

As far as the C standard is concerned, there is no requirement that
dereferencing such a pointer has defined behavior at all.
If I declare the structure

struct sockaddr_in servaddr

Not a standard C data type.
and I put in

servaddr.sin_family = AF_INET; /* which corresponds to a value */

and I put in

servaddr.sin_port = htons(13) /* which converts port 13 and assigns it
to sin_port */

Not a standard C function.

[snip]
I hope that clarifies. I am okay with setting up clients and servers;
I'm just stuck on how C is working above.

As far as C is concerned, when you play type punning you are
responsible for knowing what you are doing, with any sort of undefined
behavior as a consequence. If the members of the two structure types
are different there is a good chance that when accessing some of the
members you will be accessing objects with different lvalues than the
objects were written with. In that case, C is not working at all,
this produces undefined behavior in which case the C standard makes no
guarantees or requirements at all about what will happen.

Exactly what might or might not happen on your implementation, if it
is predictable at all, depends on a combination of at least three
things.

One of these is the definition of the data types, and neither of these
structure types are defined by standard C. They are non-standard
extensions provided by your compiler/OS, and so off-topic here.

The second factor is the underlying hardware architecture of your
platform, which is also not defined by the C standard and is off-topic
here.

The final factor is your particular compiler, and how it chooses to
act in this instance. Specific compilers are also off-topic here.

So your question is about how your specific compiler reacts when you
invoke undefined behavior by punning two non-standard structure types.
There is not one single aspect of this question that is NOT off-topic
here.

You need to ask this question in a group that supports your particular
compiler/OS combination, such as or It is just plain not a C language
question at all.
 
T

tweak

So that I can ask questions on topic, what do you consider C?

ANSI C? C99 C? K&R2 C? ISO C?

Even a simple type will change size based on the system it is
running on. How do you talk about programming C without
talking about how to write portable C software? Isn't that part
of the art? Programs like Mozilla and Apache that can run
on different systems and OS's are impressive.

Cheers,

Brian


Jack said:
in comp.lang.c:

First your title displays a fundamental misunderstanding that is
augmenting your confusion.

You _are not_ casting structures, and you _cannot_ cast structures in
C.

You can cast a pointer to any type of object to a pointer to any other
type of object at all, and that is what you are doing here.

I understand the text just fine. It's when I assign the pointer to
another pointer of the type being cast to and look at the dereferenced
values that I get confused.


As far as the C standard is concerned, there is no requirement that
dereferencing such a pointer has defined behavior at all.

If I declare the structure

struct sockaddr_in servaddr


Not a standard C data type.

and I put in

servaddr.sin_family = AF_INET; /* which corresponds to a value */

and I put in

servaddr.sin_port = htons(13) /* which converts port 13 and assigns it
to sin_port */


Not a standard C function.

[snip]

I hope that clarifies. I am okay with setting up clients and servers;
I'm just stuck on how C is working above.


As far as C is concerned, when you play type punning you are
responsible for knowing what you are doing, with any sort of undefined
behavior as a consequence. If the members of the two structure types
are different there is a good chance that when accessing some of the
members you will be accessing objects with different lvalues than the
objects were written with. In that case, C is not working at all,
this produces undefined behavior in which case the C standard makes no
guarantees or requirements at all about what will happen.

Exactly what might or might not happen on your implementation, if it
is predictable at all, depends on a combination of at least three
things.

One of these is the definition of the data types, and neither of these
structure types are defined by standard C. They are non-standard
extensions provided by your compiler/OS, and so off-topic here.

The second factor is the underlying hardware architecture of your
platform, which is also not defined by the C standard and is off-topic
here.

The final factor is your particular compiler, and how it chooses to
act in this instance. Specific compilers are also off-topic here.

So your question is about how your specific compiler reacts when you
invoke undefined behavior by punning two non-standard structure types.
There is not one single aspect of this question that is NOT off-topic
here.

You need to ask this question in a group that supports your particular
compiler/OS combination, such as or It is just plain not a C language
question at all.
 
J

Joona I Palaste

tweak said:
So that I can ask questions on topic, what do you consider C?
ANSI C? C99 C? K&R2 C? ISO C?

AFAIK "ANSI C" and "ISO C" are the same thing, and "C99 C" is a form
of "ANSI C" or "ISO C". ANSI and ISO are standards organisations, while
C99 is a standard. Therefore C89 C, C90 C and C99 C are all "ANSI C" or
"ISO C".
"K&R2 C" is pretty much the same as "ANSI C" or "ISO C" technically, but
juridically, it does not define C.

This newsgroup is only for discussion about the standard C programming
language. System-specific extensions are off-topic, no matter how great
they are.
I'll leave it to someone else to explain in more detail.

PS. Please don't top-post.
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top