Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   struct arguments to function (http://www.velocityreviews.com/forums/t955493-struct-arguments-to-function.html)

Jack 12-14-2012 07:09 AM

struct arguments to function
 
In the following code:

struct A
{
char* name;
int age;
}

struct B1
{
struct A a;
char * type;
int num;
}

struct B2
{
struct A aa;
double price;
int num;
}

void func1(struct A* a)
{
func3(a); //LINE1
//function body
}

void func2(struct B1* b)
{
//function body
}

void func3(struct B2* b)
{
//function body
}

int main(void)
{
struct B2 *b;
func1(b); //LINE2
func2(b); //LINE3
}

LINE2 is correct. LINE1 should work in this example because the func1's argument a is B2 type. How about LINE2?

Thanks.

Jack

Bart van Ingen Schenau 12-14-2012 07:36 AM

Re: struct arguments to function
 
On Thu, 13 Dec 2012 23:09:47 -0800, Jack wrote:

> In the following code:
>
> struct A
> {
> char* name;
> int age;
> }
>
> struct B1
> {
> struct A a;
> char * type;
> int num;
> }
>
> struct B2
> {
> struct A aa;
> double price;
> int num;
> }
>

void func3(struct B2* b);

> void func1(struct A* a)
> {
> func3(a); //LINE1


The compiler can not accept this call, because func3 needs a pointer to a
struct B2, but is given a pointer to a struct A and there is no
(implicit) conversion defined between the two.

If you know that `a` always refers to the initial member of a struct B2,
then you could change that line to
func3((struct B2*)a);

> //function body
> }
>
> void func2(struct B1* b)
> {
> //function body
> }
>
> void func3(struct B2* b)
> {
> //function body
> }
>
> int main(void)
> {
> struct B2 *b;
> func1(b); //LINE2

The compiler can not accept this call, because func1 needs a pointer to a
struct A, but is given a pointer to a struct B2 and there is no implicit
conversion defined between the two.
You can use an explicit conversion (cast) here, because struct B2 has a
struct A as its first member:
func1((struct A*)b);

> func2(b); //LINE3

The compiler can not accept this call, because func2 needs a pointer to a
struct B1, but is given a pointer to a struct B2 and there is no
conversion defined between the two.

> }
>
> LINE2 is correct. LINE1 should work in this example because the func1's
> argument a is B2 type. How about LINE2?


None of the marked lines is correct.
Although you can freely convert between a pointer to a structure and a
pointer to the initial element of that structure, such conversions will
never be performed implicitly.
Additionally, you might know that func1's argument always refers to the
initial element of a struct B2, but the compiler can't know that.

>
> Thanks.
>
> Jack


Bart v Ingen Schenau

James Kuyper 12-14-2012 01:01 PM

Re: struct arguments to function
 
On 12/14/2012 02:09 AM, Jack wrote:
> In the following code:
>
> struct A
> {
> char* name;
> int age;
> }
>
> struct B1
> {
> struct A a;
> char * type;
> int num;
> }
>
> struct B2
> {
> struct A aa;
> double price;
> int num;
> }
>
> void func1(struct A* a)
> {
> func3(a); //LINE1


At this point, there is no declaration of func3() in scope. In C99 or
later, a diagnostic is required. In C90, such code would be acceptable
in itself, but it would be considered as implicitly declaring func3() to
be a function taking a struct A* argument and returning an int. I've
never deliberately taken advantage of that implicit declaration, and
it's been a long time since I last accidentally used it, so I'm not sure
exactly how it worked. I don't have a copy of C90 to check - but I
believe that the implicit declaration should cause problems further
down, when the compiler discovers that the definition of func3() isn't
compatible with that implicit declaration.

I'll answer the rest of your message by assuming that you inserted a
function prototype for func3() before the first time that you called it.

> //function body
> }
>
> void func2(struct B1* b)
> {
> //function body
> }
>
> void func3(struct B2* b)
> {
> //function body
> }
>
> int main(void)
> {
> struct B2 *b;


Note: at this point b is uninitialized. You need to add something like
the following code before making any use of the value of b or the
behavior of your code would be undefined, even if none of the other
problems were present:

struct B2 b2 = {{"John", 45}, 123456.78, 90};
b = &b2;

> func1(b); //LINE2
> func2(b); //LINE3
> }
>
> LINE2 is correct.


No, it is not. func1() requires an argument of type struct A*; you're
passing it an argument of type struct B2*, and there's no implicit
conversion between those two types. A diagnostic message is required,
and if your compiler didn't produce one, you need to find out how to
raise the warning level. One legitimate way to do what you want is

func1((struct A*)b);

That has well-defined behavior because the first member of a struct B2
has the type "struct A", but that's dangerous because no diagnostic is
required if the first member of struct B2 were not of that type, even
though the result of such a mis-match is likely to be very bad. The best
way to do something like that is

func1(&b->aa);

> LINE1 should work in this example because the func1's argument a is B2 type.


No, it should not. The fact that you violated a constraint by calling
func1(b) doesn't cancel out the fact that you violated another
constraint by calling func3(a). The types don't match for either call,
so a conforming implementation of C must generate a diagnostic message,
and is not required to accept the code. If it does accept the code after
generating the message, that code is not required to work.

However, as a practical matter, if the code is accepted, it probably
will work - but you shouldn't rely upon that fact - you should write the
code correctly.

You can fix this problem by using:

func3((struct B2*)a);

> How about LINE2?


I presume, since you marked LINE3, but didn't mention it, and you
mentioned LINE2 twice, that the second mention of LINE2 was a typo for
LINE3?

LINE3 is also a constraint violation, just like the others. Unlike the
others, there's no simple fix. There is a complicated fix, with serious
restrictions on how it can be used:

Since the first member of struct B1 has the same type as the first
member of struct B2, you can access that member using either type (see
section 6.5.3.2p6) - BUT only if those two types are members of the same
union, and only within the scope of the declaration of that union type,
and only if the object you're referring to is in fact a member of a
union of that type:

// This definition must be inserted before the definition of
// func2()
union my_union
{
struct B1 b1;
struct B2 b2;
};

// This can go inside of main()
union my_union u = {.b2 = {{"Paul", 36}, "Musician", 21}};
func2((struct B1*)&u.b2);

If you do something like that, func2() can safely access b->a, but it
can't safely access any other member of that structure. Even though both
struct types have a member named 'num', and it's the third member of
each struct, and has the same type in both structs, it's not safe to
access it; 6.5.3.2p6 allows access only to a common initial sequence of
struct members with compatible types - the fact that "type" and "price"
have different types terminates the common initial sequence.
--
James Kuyper

Jack 12-16-2012 12:18 AM

Re: struct arguments to function
 
On Friday, December 14, 2012 5:01:18 AM UTC-8, James Kuyper wrote:
> On 12/14/2012 02:09 AM, Jack wrote:
>
> > In the following code:

>
> >

>
> > struct A

>
> > {

>
> > char* name;

>
> > int age;

>
> > }

>
> >

>
> > struct B1

>
> > {

>
> > struct A a;

>
> > char * type;

>
> > int num;

>
> > }

>
> >

>
> > struct B2

>
> > {

>
> > struct A aa;

>
> > double price;

>
> > int num;

>
> > }

>
> >

>
> > void func1(struct A* a)

>
> > {

>
> > func3(a); //LINE1

>
>
>
> At this point, there is no declaration of func3() in scope. In C99 or
>
> later, a diagnostic is required. In C90, such code would be acceptable
>
> in itself, but it would be considered as implicitly declaring func3() to
>
> be a function taking a struct A* argument and returning an int. I've
>
> never deliberately taken advantage of that implicit declaration, and
>
> it's been a long time since I last accidentally used it, so I'm not sure
>
> exactly how it worked. I don't have a copy of C90 to check - but I
>
> believe that the implicit declaration should cause problems further
>
> down, when the compiler discovers that the definition of func3() isn't
>
> compatible with that implicit declaration.
>
>
>
> I'll answer the rest of your message by assuming that you inserted a
>
> function prototype for func3() before the first time that you called it.
>
>
>
> > //function body

>
> > }

>
> >

>
> > void func2(struct B1* b)

>
> > {

>
> > //function body

>
> > }

>
> >

>
> > void func3(struct B2* b)

>
> > {

>
> > //function body

>
> > }

>
> >

>
> > int main(void)

>
> > {

>
> > struct B2 *b;

>
>
>
> Note: at this point b is uninitialized. You need to add something like
>
> the following code before making any use of the value of b or the
>
> behavior of your code would be undefined, even if none of the other
>
> problems were present:
>
>
>
> struct B2 b2 = {{"John", 45}, 123456.78, 90};
>
> b = &b2;
>
>
>
> > func1(b); //LINE2

>
> > func2(b); //LINE3

>
> > }

>
> >

>
> > LINE2 is correct.

>
>
>
> No, it is not. func1() requires an argument of type struct A*; you're
>
> passing it an argument of type struct B2*, and there's no implicit
>
> conversion between those two types. A diagnostic message is required,
>
> and if your compiler didn't produce one, you need to find out how to
>
> raise the warning level. One legitimate way to do what you want is
>
>
>
> func1((struct A*)b);
>
>
>
> That has well-defined behavior because the first member of a struct B2
>
> has the type "struct A", but that's dangerous because no diagnostic is
>
> required if the first member of struct B2 were not of that type, even
>
> though the result of such a mis-match is likely to be very bad. The best
>
> way to do something like that is
>
>
>
> func1(&b->aa);
>
>
>
> > LINE1 should work in this example because the func1's argument a is B2 type.

>
>
>
> No, it should not. The fact that you violated a constraint by calling
>
> func1(b) doesn't cancel out the fact that you violated another
>
> constraint by calling func3(a). The types don't match for either call,
>
> so a conforming implementation of C must generate a diagnostic message,
>
> and is not required to accept the code. If it does accept the code after
>
> generating the message, that code is not required to work.
>
>
>
> However, as a practical matter, if the code is accepted, it probably
>
> will work - but you shouldn't rely upon that fact - you should write the
>
> code correctly.
>
>
>
> You can fix this problem by using:
>
>
>
> func3((struct B2*)a);
>
>
>
> > How about LINE2?

>
>
>
> I presume, since you marked LINE3, but didn't mention it, and you
>
> mentioned LINE2 twice, that the second mention of LINE2 was a typo for
>
> LINE3?
>
>
>
> LINE3 is also a constraint violation, just like the others. Unlike the
>
> others, there's no simple fix. There is a complicated fix, with serious
>
> restrictions on how it can be used:
>
>
>
> Since the first member of struct B1 has the same type as the first
>
> member of struct B2, you can access that member using either type (see
>
> section 6.5.3.2p6) - BUT only if those two types are members of the same
>
> union, and only within the scope of the declaration of that union type,
>
> and only if the object you're referring to is in fact a member of a
>
> union of that type:
>
>
>
> // This definition must be inserted before the definition of
>
> // func2()
>
> union my_union
>
> {
>
> struct B1 b1;
>
> struct B2 b2;
>
> };
>
>
>
> // This can go inside of main()
>
> union my_union u = {.b2 = {{"Paul", 36}, "Musician", 21}};
>
> func2((struct B1*)&u.b2);


Thanks. Even if using union, we still can not access B1's member,right? like:
((struct B1*)&u.b2)->type

Jack

James Kuyper 12-16-2012 02:48 AM

Re: struct arguments to function
 
Could you please find a better newsreader - google groups double-spaced
your response, making it hard to read.

On 12/15/2012 07:18 PM, Jack wrote:
> On Friday, December 14, 2012 5:01:18 AM UTC-8, James Kuyper wrote:
>> On 12/14/2012 02:09 AM, Jack wrote:
>>
>>> In the following code:

>>
>>> struct A
>>> {
>>> char* name;
>>> int age;
>>> }

>>
>>> struct B1
>>> {
>>> struct A a;
>>> char * type;
>>> int num;
>>> }

>>
>>> struct B2
>>> {
>>> struct A aa;
>>> double price;
>>> int num;
>>> }
>>>
>>> void func1(struct A* a)
>>> {
>>> func3(a); //LINE1

....
>>> //function body
>>> }
>>>
>>> void func2(struct B1* b)
>>> {
>>> //function body
>>> }
>>>
>>> void func3(struct B2* b)
>>> {
>>> //function body
>>> }
>>>
>>> int main(void)
>>> {
>>> struct B2 *b;

....
[my patch:]
>> struct B2 b2 = {{"John", 45}, 123456.78, 90};
>> b = &b2;


....
>>> func1(b); //LINE2
>>> func2(b); //LINE3
>>> }

....
>> LINE3 is also a constraint violation, just like the others. Unlike the
>> others, there's no simple fix. There is a complicated fix, with serious
>> restrictions on how it can be used:
>>
>> Since the first member of struct B1 has the same type as the first
>> member of struct B2, you can access that member using either type (see
>> section 6.5.3.2p6) - BUT only if those two types are members of the same
>> union, and only within the scope of the declaration of that union type,
>> and only if the object you're referring to is in fact a member of a
>> union of that type:
>>
>> // This definition must be inserted before the definition of
>> // func2()
>> union my_union
>> {
>> struct B1 b1;
>> struct B2 b2;
>> };
>>
>> // This can go inside of main()
>> union my_union u = {.b2 = {{"Paul", 36}, "Musician", 21}};


Sorry - I got mixed up; "Musician" should be replaced with a floating
point initializer for u.b2.price, such as 3.21.

>> func2((struct B1*)&u.b2);

>
> Thanks. Even if using union, we still can not access B1's member,right? like:
> ((struct B1*)&u.b2)->type


Well, yes. As I said above, there are serious restrictions on the use of
this approach. The only things you can access are u.b2.aa, u.b2.price,
u.b2.num and u.b1.a (which is the same as u.b2.aa).
Neither u.b1.type nor u.b1.num has been set to any particular value. The
memory that would have been used to store their values, if they been
given any, may currently be in use to store some other values (depending
upon how much padding the compiler inserts into struct B1 and struct B2,
and where).

Your question was very abstract - if it reflects an issue that's come up
while you were trying to solve some problem, there's a pretty good
chance that the right solution looks quite a bit different.
--
James Kuyper


All times are GMT. The time now is 01:25 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.