• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 575
  • Last Modified:

Typecasting of structures...

Hi I am delving in to network programming and having difficulty in understanding the typecasting effects:

E.g the function is:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

and we are passing the following:

accept(sock, (struct sockaddr *)&client, &len))

for struct sockaddr *add, can't i just pass the
address &client, instead of typecasting it with
 (struct sockaddr *), what does typecasting mean in this case.

Thanks.
0
tpat
Asked:
tpat
  • 4
  • 2
  • 2
  • +2
4 Solutions
 
phoffricCommented:
From http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html
include <netinet/in.h>
// All pointers to socket address structures are often cast to pointers
// to this type before use in various functions and system calls:
struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

// IPv4 AF_INET sockets:
struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

Open in new window

In the accept function, addr is expected to be of the data type, struct sockaddr *

From http://www.linuxhowtos.org/C_C++/socket.htm are these two LOCS:
struct sockaddr_in serv_addr, cli_addr;
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

Open in new window

Without the (struct sockaddr *) cast, you should get a compiler warning or error due to mismatch pointer types. There is no functional effect to the generated assembly code when using the type cast - the address of cli_addr is passed to accept. The type cast just serves to get past the compiler step.
0
 
tpatAuthor Commented:
So you mean that functionally it does not make any difference if i use/do not
use the typecast, however to get the way out of compiler error/warning,
we need to use the typecast.

Appreciate you help! Thanks.

-Tejas
0
 
phoffricCommented:
Right, what the accept needs is the address of cli_addr to fill up the cli_addr structure. However, it accepts a pointer to a different structure that represents an address family, AF_xxx , not necessarily struct sockaddr_in.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
phoffricCommented:
For example, in the http://beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html link is this IPv6 structure:
// IPv6 AF_INET6 sockets:
struct sockaddr_in6 {
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

Open in new window

"the struct sockaddr_in and struct sockaddr_in6 share the same beginning structure as struct sockaddr, and you can freely cast the pointer of one type to the other without any harm"

"whenever a function says it takes a struct sockaddr* you can cast your struct sockaddr_in*, struct sockaddr_in6*, or struct sockadd_storage* to that type with ease and safety."
But just make sure that the socklen_t *addrlen argument in accept is large enough to handle the struct that you are using.

This accept link ( http://beej.us/guide/bgnet/output/html/multipage/syscalls.html#accept ) shows how to handle either IPv4 or IPv6, when the modality is unspecified. The above IPv6 structure is larger than the IPv4 struct. But if you follow the pattern in this link, you should have no problem. (I'll take this on faith, for now, since I haven't worked with IPv6.)
struct sockaddr_storage their_addr;
socklen_t addr_size;
addr_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);

Open in new window

0
 
ssnkumarCommented:
The socket calls - socket(), bind(), listen(), accept() and connect() - are common to both internet domain and unix domain.
But, both these domains have different kind of structures:
Internet Domain uses:
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;                 /* Port number.  */
    struct in_addr sin_addr;            /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                           __SOCKADDR_COMMON_SIZE -
                           sizeof (in_port_t) -
                           sizeof (struct in_addr)];
  };

Unix Domain uses:
struct sockaddr_un
  {
    __SOCKADDR_COMMON (sun_);
    char sun_path[108];         /* Path name.  */
  };

Now, how to use two different structs as parameters in both kinds of domains.
To get it working for both, they created a general structure:
struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

And while calling these functions, typecast the correct struct.
Internally, based on the type of domain we are using, the functions will inturn typecast "struct sockaddr" to correct structure and uses it.
0
 
tpatAuthor Commented:
If that is so,
can I use accept(sock, (struct sockaddr_inet *)&client, &len)) instead of
accept(sock, (struct sockaddr *)&client, &len)).

Thanks
0
 
ssnkumarCommented:
> can I use accept(sock, (struct sockaddr_inet *)&client, &len))
I don't think, there is any structure "struct sockaddr_inet".
The prototype for accept() is:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
So, while calling accept, you will have to use the same struct that is used in the prototype to typecast.
So, you should use:
accept(sock, (struct sockaddr *)&client, &len))
0
 
phoffricCommented:
By any chance, are you referring to Windows Winsock API? I found a SOCKADDR_INET union that is defined on Windows Vista and later. (Haven't used it myself.)
But SOCKADDR_INET is a union rather than a struct.
Here is the definition of SOCKADDR_INET:
typedef union _SOCKADDR_INET {
  SOCKADDR_IN    Ipv4;
  SOCKADDR_IN6   Ipv6;
  ADDRESS_FAMILY si_family;
} SOCKADDR_INET, *PSOCKADDR_INET;

Open in new window

   http://msdn.microsoft.com/en-us/library/aa814468(v=vs.85).aspx

In Windows, their accept is:
SOCKET accept(
  __in     SOCKET s,
  __out    struct sockaddr *addr,
  __inout  int *addrlen
);

Open in new window

   http://msdn.microsoft.com/en-us/library/ms737526(v=VS.85).aspx
So, you still want a struct sockaddr * for the 2nd argument.
0
 
eagerCommented:
tpat -- to get back to your question about the effect of typecasting pointers in C.

All pointers in C have the same identical implementation.  All pointers have the same format and same size.   Typecasting a pointer doesn't change its format.

The C compiler catches common programming errors which occur when you pass pointers to one kind of object to a function which expects a different kind of object.  The typecast allows you to tell the compiler that you know that the object is one type but you are sure that it is compatible with some other type.  In this way, casting a pointer makes it more difficult for the compiler to catch errors.  Any time you find that you need to insert a typecast for a pointer, you loose some error checking so you need to be much more careful to be sure that it is correct.  

Good APIs don't require casting pointers.  The socket API is old was not implemented consistently, which leads to requiring typecasting pointers.
0
 
Duncan RoeSoftware DeveloperCommented:
Agree with the general rule to avoid type casting where practicable, but casting sockaddr_in to sockaddr is a classic programming construct - everybody does it
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 2
  • 2
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now