473,473 Members | 1,488 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

To coerce or not...? struct sockaddr vs struct sockaddr_in

Having updated my Debian system it now complains that I am using
an incompatible pointer type in warnings such as "passing arg 2
of 'bind' from incompatible pointer type" from code,

struct sockaddr_in sockad1;
....
retval = bind (sock1, &sockad1, sockad1len);

I can coerce the pointer with

retval = bind (sock1, (struct sockaddr *) &sockad1, sockad1len);

but that seems to me to be bad style - doesn't it overrides the
compiler's checking? I cannot instead change the defintion to
struct sockaddr sockad1 because my code uses members of the
sockaddr_in structure. Any other resolution I can think of is
messy. Why cannot the compiler accept that a pointer to a struct
sockaddr_in IS compatible with a pointer to struct sockaddr?
Should I coerce to keep the compiler happy or is there a better
way to approch the problem?

TIA,
- James
Nov 13 '05 #1
4 12038
James Harris <no.email.please> wrote:
Having updated my Debian system it now complains that I am using
an incompatible pointer type in warnings such as "passing arg 2
of 'bind' from incompatible pointer type" from code,

struct sockaddr_in sockad1;
...
retval = bind (sock1, &sockad1, sockad1len);

I can coerce the pointer with

retval = bind (sock1, (struct sockaddr *) &sockad1, sockad1len);

but that seems to me to be bad style - doesn't it overrides the
compiler's checking?
Yes, it is. But the bad style is not yours; it is the sockets API
you're using that is the root cause (it should have used a pointer to
union instead).
I cannot instead change the defintion to
struct sockaddr sockad1 because my code uses members of the
sockaddr_in structure. Any other resolution I can think of is
messy. Why cannot the compiler accept that a pointer to a struct
sockaddr_in IS compatible with a pointer to struct sockaddr?
Because C doesn't work that way. Pointers to different structs are
never assignment-compatible.
Should I coerce to keep the compiler happy or is there a better
way to approch the problem?


Since you can't change the signature of the function, the cast is the
best solution. If you're concerned about the possibility of the cast
hiding errors, you can reduce it to one instance of the cast in your
entire code (I'm making an educated guess as to the signature of the
bind function you're calling):

int bind_in(int sockfd, struct sockaddr_in *my_addr, socklen_t addrlen)
{
return bind(sockfd, (struct sockaddr *)my_addr, addrlen);
}

Then just call bind_in() instead of bind() whenever you're using a
sockaddr_in. The only cast to get right is the one in bind_in() - the
compiler will warn you if you try to pass anything other than struct
sockaddr_in * as the second parameter of bind_in().

- Kevin.

Nov 13 '05 #2
Kevin, Many thanks for your help. It all makes a bit more sense
now!

"Kevin Easton" <kevin@-nospam-pcug.org.au> wrote in message
news:ne********************@tomato.pcug.org.au...
<snip>
Because C doesn't work that way. Pointers to different structs are never assignment-compatible.


Does this just happen for structs? The third parameter seems to
accept any of int, long etc and perversely char, float and
double, as well as any size_X parameter. How can bind be
expected to make sense of a float???

I notice from the headers that socklen_t is defined from
__socklen_t which is declared as typedef unsigned int. Would I
be right in assuming that the compiler generates code to convert
between float and unsigned int? The code works with this as a
float. Horrible.

....I have since been looking at the generated assembler and
compilation of the line
retval = bind (sock1, (struct sockaddr *) &mysock, mysocklen);
generates the following in gcc 2.95.4. The line with a - is the
line used when mysocklen is an integer, a long, or a socklen_t
(all compile identically). The lines with a + replace that line
when s1len is declared as a float. I think the fistpll writes
the float as an integer, which goes in to EDX before finding its
way to EAX and being pushed, thus converting before making the
call. Note to self: if you want fast code be careful to use
integer if that's what your library calls expect.(!)
addl $-4,%esp
- movl -152(%ebp),%eax
+ flds -152(%ebp)
+ fnstcw -670(%ebp)
+ movw -670(%ebp),%ax
+ orw $3072,%ax
+ movw %ax,-672(%ebp)
+ fldcw -672(%ebp)
+ fistpll -680(%ebp)
+ movl -680(%ebp),%edx
+ movl -676(%ebp),%ecx
+ fldcw -670(%ebp)
+ movl %edx,%eax
pushl %eax
leal -116(%ebp),%eax
pushl %eax
movl -512(%ebp),%eax
pushl %eax
call bind
addl $16,%esp
movl %eax,%eax
movl %eax,-56(%ebp)
Nov 13 '05 #3
>"Kevin Easton" <kevin@-nospam-pcug.org.au> wrote in message
news:ne********************@tomato.pcug.org.au. ..
... Pointers to different structs are never assignment-compatible.

In article <3f***********************@lovejoy.zen.co.uk>,
James Harris <no.email.please> wrote:Does this just happen for structs?
Structures and unions (and "enum"s, to some extent). The reason
that "pointer to struct X" and "pointer to struct Y" are not
compatible is that the first occurrence of "struct X" creates a
new type -- the type named "struct X" -- and then "struct Y" creates
another new type, the one named "struct Y". Since these are two
new types, they must be different types, even if the contents are
the same.

As Kevin Easton said, the socket interface is not very well designed,
and as a result you *must* cast (or take a trip through "void *")
in at least one place. (The type-safety, or lack thereof, is just
one aspect of where the original BSD socket interface goes wrong.
If I could go back in time and fix it, I would try to convince
someone to replace the bind(), connect(), and listen() calls with
a single call. But this is different problem entirely, having
nothing to do with C per se.)
The third parameter seems to
accept any of int, long etc and perversely char, float and
double, as well as any size_X parameter. How can [function F] be
expected to make sense of a float???


The actual name of "function F" is not relevant here but its
prototype, if it has one -- and apparently it does on your system
-- is. That prototype is:

typedef unsigned int some_integral_type; /* as it happens */
int F(int, struct S *, some_integral_type);

In C, any call to a function that has a prototype in scope at
the point of the call makes use of the types in the prototype.
They cause each actual parameter in the call to be passed "as
if by ordinary assignment".

If you write:

int i;
float f = 3.14;

and then write:

i = f;

this instructs the compiler to truncate the ".14" part, leaving
just 3, and assigning 3 to i -- using whatever machine code sequence
is required to do that. (If the compiler can prove to itself that
this sets i to 3, this could be as simple as "move constant_3 =>
register holding i" or some such, rather than the 11 lines of
x86 assembly I will refrain from quoting. :-) )

Since a prototyped call is "just like" assignment, a call of the
form:

extern void zog(int);
zog(f);

must likewise "assign" 3 to zog's formal parameter:

void zog(int i) { printf("zog got %d\n", i); }

On the other hand, if you omit the prototype, or fail to declare
zog() at all, then -- in C89 only -- no diagnostic is required and
the behavior is undefined. (In C99 "failure to declare zog()"
requires a diagnostic; declaring it without a prototype still
produces undefined behavior.) In practice, C compilers treat
this in the same way as calls to prototyped-but-variadic functions,
so that:

extern void zog(); /* note lack of prototype */
zog(f);

widens the value in f (still 3.14) to "double" -- changing its
representation in memory and/or registers if needed, as is the case
on the x86 -- and this works right only if zog() tries to access
the provided "double". Grabbing an "int", when the compiler passed
a "double", remains undefined, but does one of two different things
in practice: it either gets sizeof(int) bytes out of the sizeof(double)
bytes passed, or it gets an apparently-random value out of some
unset memory (typically, a "wrong register" or "wrong stack" --
e.g., an x86 compiler might pass the "double" on the FPU stack
instead of the stack at %esp, so that the "int" zog() reads at
(%esp+K) for some constant K has nothing to do with the 3.14 in
the FPU stack).

Ultimately, this boils down to a few simple rules C programmers
can follow.

- Always use complete prototypes whenever possible. Calls
to prototyped functions act like ordinary assignments,
in terms of the values passed in.

- Beware of variadic functions, which effectively have
no prototypes beyond the fixed-argument portion. The
varying arguments are "widened", so that float becomes
double, and char and short become int. The exact rules
get a bit complicated (does "unsigned short" widen to
signed int or unsigned int? this turns out to be
implementation-dependent!), and C99 introduces a new
concept of "type rank" along with its horde of new
types (long long, and all the complex types).

- Compile with the "warn me if I forgot to prototype"
option, so that you get A, instead of B. :-)

- Define new types with "struct". The "typedef" keyword
is misleading: it means "do not define a new type". :-)
(It defines aliases for *existing* types. In "typedef
struct S { ... } alias;", it is the "struct" part that
defines the new type.)
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 13 '05 #4
Chris,
You've touched upon a number of issues which strike a chord but
I'll maybe come back and raise some questions on them another
time. Thanks for the help just now.
- James
"Chris Torek" <no****@elf.eng.bsdi.com> wrote in message
news:bm**********@elf.eng.bsdi.com...
"Kevin Easton" <kevin@-nospam-pcug.org.au> wrote in message
news:ne********************@tomato.pcug.org.au. ..
... Pointers to different structs are never
assignment-compatible.

In article <3f***********************@lovejoy.zen.co.uk>,
James Harris <no.email.please> wrote:
Does this just happen for structs?
Structures and unions (and "enum"s, to some extent). The

reason that "pointer to struct X" and "pointer to struct Y" are not
compatible is that the first occurrence of "struct X" creates a new type -- the type named "struct X" -- and then "struct Y" creates another new type, the one named "struct Y". Since these are two new types, they must be different types, even if the contents are the same.

As Kevin Easton said, the socket interface is not very well designed, and as a result you *must* cast (or take a trip through "void *") in at least one place. (The type-safety, or lack thereof, is just one aspect of where the original BSD socket interface goes wrong. If I could go back in time and fix it, I would try to convince
someone to replace the bind(), connect(), and listen() calls with a single call. But this is different problem entirely, having
nothing to do with C per se.)
The third parameter seems to
accept any of int, long etc and perversely char, float and
double, as well as any size_X parameter. How can [function F]
beexpected to make sense of a float???


The actual name of "function F" is not relevant here but its
prototype, if it has one -- and apparently it does on your

system -- is. That prototype is:

typedef unsigned int some_integral_type; /* as it happens */ int F(int, struct S *, some_integral_type);

In C, any call to a function that has a prototype in scope at
the point of the call makes use of the types in the prototype.
They cause each actual parameter in the call to be passed "as
if by ordinary assignment".

If you write:

int i;
float f = 3.14;

and then write:

i = f;

this instructs the compiler to truncate the ".14" part, leaving just 3, and assigning 3 to i -- using whatever machine code sequence is required to do that. (If the compiler can prove to itself that this sets i to 3, this could be as simple as "move constant_3 => register holding i" or some such, rather than the 11 lines of
x86 assembly I will refrain from quoting. :-) )

Since a prototyped call is "just like" assignment, a call of the form:

extern void zog(int);
zog(f);

must likewise "assign" 3 to zog's formal parameter:

void zog(int i) { printf("zog got %d\n", i); }

On the other hand, if you omit the prototype, or fail to declare zog() at all, then -- in C89 only -- no diagnostic is required and the behavior is undefined. (In C99 "failure to declare zog()"
requires a diagnostic; declaring it without a prototype still
produces undefined behavior.) In practice, C compilers treat
this in the same way as calls to prototyped-but-variadic functions, so that:

extern void zog(); /* note lack of prototype */
zog(f);

widens the value in f (still 3.14) to "double" -- changing its
representation in memory and/or registers if needed, as is the case on the x86 -- and this works right only if zog() tries to access the provided "double". Grabbing an "int", when the compiler passed a "double", remains undefined, but does one of two different things in practice: it either gets sizeof(int) bytes out of the sizeof(double) bytes passed, or it gets an apparently-random value out of some unset memory (typically, a "wrong register" or "wrong stack" -- e.g., an x86 compiler might pass the "double" on the FPU stack
instead of the stack at %esp, so that the "int" zog() reads at
(%esp+K) for some constant K has nothing to do with the 3.14 in the FPU stack).

Ultimately, this boils down to a few simple rules C programmers can follow.

- Always use complete prototypes whenever possible. Calls
to prototyped functions act like ordinary assignments,
in terms of the values passed in.

- Beware of variadic functions, which effectively have
no prototypes beyond the fixed-argument portion. The
varying arguments are "widened", so that float becomes
double, and char and short become int. The exact rules
get a bit complicated (does "unsigned short" widen to
signed int or unsigned int? this turns out to be
implementation-dependent!), and C99 introduces a new
concept of "type rank" along with its horde of new
types (long long, and all the complex types).

- Compile with the "warn me if I forgot to prototype"
option, so that you get A, instead of B. :-)

- Define new types with "struct". The "typedef" keyword
is misleading: it means "do not define a new type". :-)
(It defines aliases for *existing* types. In "typedef
struct S { ... } alias;", it is the "struct" part that
defines the new type.)
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering) Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603 email: forget about it http://67.40.109.61/torek/index.html (for the moment) Reading email is like searching for food in the garbage,

thanks to spammers.
Nov 13 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: bradleyc | last post by:
I have seen this is mainly linked lists ... something like struct NodeType { int current NodeType *next } So you are obviously able to use the struct within itself?
6
by: Fernan Bolando | last post by:
What is the best way of passing a structure to a function currently I do by it passing a pointer to the structe. sample code below int main() { struct sample_struct a_struct, *point_struct;...
3
by: Michael B Allen | last post by:
Consider the following structures: struct bar { int i; float f; unsigned char tail; }; struct foo { struct bar b1; unsigned char _b1tail;
1
by: Jón Sveinsson | last post by:
Hello everone I have code from c which I need to convert to c#, the c code is following, as you can see there is a struct inside struct typedef struct { some variables....
1
by: Okko Willeboordse | last post by:
typedef struct _RDATA { struct RDATA *pRDATA; } RDATA, *PRDATA; How to compile with a C++ compiler?
3
by: kritikapoor | last post by:
Hi, i have a structure like this: struct SC { const int address ; const int pad ;
8
by: FBM | last post by:
Hi there, I am puzzled with the behavior of my code.. I am working on a networking stuff, and debugging with eclipse (GNU gdb 6.6-debian).. The problem I am experiencing is the following: ...
2
by: ice88 | last post by:
i have problem in define struct within struct struct student_detail { int id; string name; }; struct subject_detail
1
by: metalheadstorm | last post by:
There isn't much explaining to this, this is what I have: public struct PACKET_HEADER { public string computerIp; public string computerName; public string...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.