Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   macro to access structure's member (http://www.velocityreviews.com/forums/t754974-macro-to-access-structures-member.html)

Mark 10-17-2011 06:22 PM

macro to access structure's member
 
Hello

I have a structure and made up a small macro to access it member. Is it safe
way to use it to increment it?

struct foo
{
int a;
int b;
int c;
};
#define FOO_A(s) ((s).a)

struct foo foo1;
printf("-> %d %d\n", FOO_A(foo1), ++FOO_A(foo1));

The result is correct, but I'm not sure about side effects though if any.
Also FOO_A(foo1)++ doesn't seem to work, I don't understand why. Would be
helpful for advices and comments, thank you !

Mark



Fred 10-17-2011 06:36 PM

Re: macro to access structure's member
 
On Oct 17, 11:22*am, "Mark" <mark_cruzNOTFORS...@hotmail.com> wrote:
> Hello
>
> I have a structure and made up a small macro to access it member. Is it safe
> way to use it to increment it?
>
> struct foo
> {
> * * int a;
> * * int b;
> * * int c;};
>
> #define FOO_A(s) *((s).a)
>
> struct foo foo1;
> printf("-> %d *%d\n", FOO_A(foo1), *++FOO_A(foo1));
>
> The result is correct


Can't possibly be correct, since you haven't initialized foo1.a to
anything.

> but I'm not sure about side effects though if any.


And so you should be worried here. Even if you had initialized it, it
is undefined behavior. You didn't define what "correct" is; undefined
behavior may look "correct" even when it isn't.

> Also FOO_A(foo1)++ *doesn't seem to work, I don't understand why. Wouldbe
> helpful for advices and comments, thank you !
>


"doesn't seem to work" - what were you expecting, and why were you
expecting that?

What were the actual results, and how were they different than what
you expected?

The problem has nothing to do with the use of the macro.

What wopuld you expect with:

printf("-> %d %d\n", foo1.a, ++foo1.a);
and
printf("-> %d %d\n", foo1.a, foo1.a++);

other than undefined behavior?

--
Fred K



Mark 10-17-2011 08:09 PM

Re: macro to access structure's member
 

"Fred" <fred.l.kleinschmidt@boeing.com> wrote in message
news:e28c6616-4484-4bf6-8b5a-33176f3c5102@h23g2000pra.googlegroups.com...
>> struct foo foo1;
>> printf("-> %d %d\n", FOO_A(foo1), ++FOO_A(foo1));
>>
>> The result is correct


> Can't possibly be correct, since you haven't initialized foo1.a to
> anything.


foo1 is global object and thus all members are initialized to 0.

>> but I'm not sure about side effects though if any.


> And so you should be worried here. Even if you had initialized it, it
> is undefined behavior. You didn't define what "correct" is; undefined
> behavior may look "correct" even when it isn't.


I expected to have member 'a' of teh structure 'struct foo' to be
incremented, i.e. 'foo1.a' yields a current value of 'a' and then I
increment the value -- this was my expectation. Where is my reasoning wrong
?


> The problem has nothing to do with the use of the macro.


> What wopuld you expect with:


> printf("-> %d %d\n", foo1.a, ++foo1.a);
> and
> printf("-> %d %d\n", foo1.a, foo1.a++);


> other than undefined behavior?


But in my macro I have parentheses around, i.e. (foo1.a)++.

--
Fred K




Morris Keesan 10-17-2011 08:36 PM

Re: macro to access structure's member
 
On Mon, 17 Oct 2011 16:09:22 -0400, Mark <mark_cruzNOTFORSPAM@hotmail.com>
wrote:

>
> "Fred" <fred.l.kleinschmidt@boeing.com> wrote in message


>> What wopuld you expect with:

>
>> printf("-> %d %d\n", foo1.a, ++foo1.a);
>> and
>> printf("-> %d %d\n", foo1.a, foo1.a++);

>
>> other than undefined behavior?

>
> But in my macro I have parentheses around, i.e. (foo1.a)++.


The parentheses don't matter in this case. The
structure-member-selection operator (.) binds tighter than the
increment operator. The problem can be reduced to

printf("%d %d\n", i, ++i); or printf("%d %d\n", i, ++i);

You're evaluating i (or foo1.a) and modifying it, both within the
call to printf, between sequence points.
See the first few questions at

http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=expr

for a discussion of this issue.
--
Morris Keesan -- mkeesan@post.harvard.edu

Keith Thompson 10-17-2011 08:45 PM

Re: macro to access structure's member
 
"Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:
> "Fred" <fred.l.kleinschmidt@boeing.com> wrote in message
> news:e28c6616-4484-4bf6-8b5a-33176f3c5102@h23g2000pra.googlegroups.com...
>>> struct foo foo1;
>>> printf("-> %d %d\n", FOO_A(foo1), ++FOO_A(foo1));
>>>
>>> The result is correct

>
>> Can't possibly be correct, since you haven't initialized foo1.a to
>> anything.

>
> foo1 is global object and thus all members are initialized to 0.


Ok. That wasn't clear from your original post; the declaration of foo1
appeared to be at the same scope as the printf call.

>>> but I'm not sure about side effects though if any.

>
>> And so you should be worried here. Even if you had initialized it, it
>> is undefined behavior. You didn't define what "correct" is; undefined
>> behavior may look "correct" even when it isn't.

>
> I expected to have member 'a' of teh structure 'struct foo' to be
> incremented, i.e. 'foo1.a' yields a current value of 'a' and then I
> increment the value -- this was my expectation. Where is my reasoning wrong
> ?
>
>
>> The problem has nothing to do with the use of the macro.

>
>> What wopuld you expect with:

>
>> printf("-> %d %d\n", foo1.a, ++foo1.a);
>> and
>> printf("-> %d %d\n", foo1.a, foo1.a++);

>
>> other than undefined behavior?

>
> But in my macro I have parentheses around, i.e. (foo1.a)++.


The parentheses aren't the point; Fred was only talking about foo1 being
uninitialized (which apparerently is not an issue).

You wrote, "Also FOO_A(foo1)++ doesn't seem to work, I don't understand
why". You should be aware that that's nearly the least useful statement
you could make. You didn't tell us what it did, or what you expected it
to do, or how those differed. Fred asked:

What were the actual results, and how were they different than what
you expected?

You never answered.

Here's what I *think* is going on. You write:

printf("-> %d %d\n", foo1.a, FOO_A(foo1)++);

and it worked exactly as it should, but you thought it should behave
differently. As Fred said, that's exactly equivalent to:

printf("-> %d %d\n", foo1.a, foo1.a++);

Since the initial value of foo.a is 0 (that's new information),
"foo1.a++" will have the side effect of incrementing foo.a, setting it
to 1. But the result of the postfix "++" operator is the value of the
operand *before* it's incremented, so the value printed will be 0. (If
that weren't the case, there would be no point in having prefix and
postfix versions of "++"; they'd both do the same thing.)

But there is another problem, and as Fred points out the behavior of

printf("-> %d %d\n", foo1.a, foo1.a++);

is undefined. It reads and modifies foo.a twice without an
intervening sequence point (in the second and third arguments,
respectively), and the value it reads isn't used to determine the
value to be written. The side effect of the increment could happen
either before or after the evaluation of the second argument.
Rather than just permitting evaluation to occur in either order,
the standard makes the behavior completely undefined; literally
anything could happen.

You can fix this by splitting it into two printf calls:

printf("--> %d", foo1.a);
printf(" %d\n", foo1.a++);

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Fred 10-17-2011 08:46 PM

Re: macro to access structure's member
 
On Oct 17, 1:09*pm, "Mark" <mark_cruzNOTFORS...@hotmail.com> wrote:
> "Fred" <fred.l.kleinschm...@boeing.com> wrote in message
>
> news:e28c6616-4484-4bf6-8b5a-33176f3c5102@h23g2000pra.googlegroups.com...
>
> >> struct foo foo1;
> >> printf("-> %d %d\n", FOO_A(foo1), ++FOO_A(foo1));

>
> >> The result is correct

> > Can't possibly be correct, since you haven't initialized foo1.a to
> > anything.

>
> foo1 is global object and thus all members are initialized to 0.
>
> >> but I'm not sure about side effects though if any.

> > And so you should be worried here. Even if you had initialized it, it
> > is undefined behavior. You didn't define what "correct" is; undefined
> > behavior may look "correct" even when it isn't.

>
> I expected to have member 'a' of teh structure 'struct foo' to be
> incremented, *i.e. 'foo1.a' yields a current value of 'a' and then I
> increment the value -- this was my expectation. Where is my reasoning wrong
> ?
>
> > The problem has nothing to do with the use of the macro.
> > What wopuld you expect with:
> > printf("-> %d *%d\n", foo1.a, *++foo1.a);
> > and
> > printf("-> %d *%d\n", foo1.a, *foo1.a++);
> > other than undefined behavior?

>
> But in my macro I have parentheses around, i.e. (foo1.a)++


You are still invoking undefined behavior by trying to modify foo1.a
in the same statement that you also read it, without a sequence point
between them.

What would uyou expect from
int a=1;
myFunction( a, ++a );
or
myOtherFuncton( a, a++ );
?

How about
anotherFunction( foo(a), bar(a) );


Do you expect myFunction to receive (1,2) or (2,2) as its arguments?
Do you expect myOtherFunction to receive (1,1) or (2,1) ?

In calling anotherFunction() above, it is arbitrary whether foo(a) is
called first, or bar(a) is called first, before calling
anotherFunction.

The same thing applies to the calls to myFunction and myOtherFunction
- The compiler is free to evaluate either argument first - including
applying the side effects - before evaluating the other argument.

--
Fred K

Keith Thompson 10-17-2011 10:05 PM

Re: macro to access structure's member
 
"Morris Keesan" <mkeesan@post.harvard.edu> writes:
[...]
> The parentheses don't matter in this case. The
> structure-member-selection operator (.) binds tighter than the
> increment operator. The problem can be reduced to
>
> printf("%d %d\n", i, ++i); or printf("%d %d\n", i, ++i);
>
> You're evaluating i (or foo1.a) and modifying it, both within the
> call to printf, between sequence points.
> See the first few questions at
>
> http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=expr
>
> for a discussion of this issue.


Reading and modifying an object between sequence points doesn't always
cause undefined behavior. It does in this case because the value that's
read isn't used to compute the value to be stored.

For example:

i = i * 2;

is ok, because the modification of i *can't* take place until after
the evaluation of the previous value is complete. (This required
sequencing implicit in C90 and C99; C201X makes it explicit.)

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Nick Keighley 10-18-2011 09:03 AM

Re: macro to access structure's member
 
On Oct 17, 9:46*pm, Fred <fred.l.kleinschm...@boeing.com> wrote:
> On Oct 17, 1:09*pm, "Mark" <mark_cruzNOTFORS...@hotmail.com> wrote:
> > "Fred" <fred.l.kleinschm...@boeing.com> wrote in message
> >news:e28c6616-4484-4bf6-8b5a-33176f3c5102@h23g2000pra.googlegroups.com....



> > >> struct foo foo1;
> > >> printf("-> %d %d\n", FOO_A(foo1), ++FOO_A(foo1));

>
> > >> The result is correct
> > > Can't possibly be correct, since you haven't initialized foo1.a to
> > > anything.

>
> > foo1 is global object and thus all members are initialized to 0.

>
> > >> but I'm not sure about side effects though if any.
> > > And so you should be worried here. Even if you had initialized it, it
> > > is undefined behavior.


Note Well: the construct exhibits Undefined Behaviour. The Implementor
is permitted to do as He Damn Well Pleases (TM).

<snip>

> You are still invoking undefined behavior by trying to modify foo1.a
> in the same statement that you also read it, without a sequence point
> between them.
>
> What would uyou expect from
> * *int a=1;
> * *myFunction( a, ++a );
> or
> * *myOtherFuncton( a, a++ );
> ?
>
> How about
> * anotherFunction( foo(a), bar(a) );
>
> Do you expect myFunction to receive (1,2) or (2,2) as its arguments?


or something even more bizzare and unexpected. UB isn't limited to
just (1,2) or (2,2) or (a-suffusion-of-yellow, a-suffusion-of-yellow)

> Do you expect myOtherFunction to receive (1,1) or (2,1) ?


ditto

> In calling anotherFunction() above, it is arbitrary whether foo(a) is
> called first, or bar(a) is called first, before calling
> anotherFunction.


this merely implementation defined behaviour. At least the
possibilities are limited either one case ot the other (assuming foo
and bar have reasonable behaviour).

> The same thing applies to the calls to myFunction and myOtherFunction


no not really


> - The compiler is free to evaluate either argument first - including
> applying the side effects - before evaluating the other argument.


it's permitted far more freedom than this! I bet CERN's FTL neutrino's
turn out to be some bizzare effect of Undefined Behaviour.

We're doomed... doomed I say...

Mark 10-19-2011 02:22 AM

Re: macro to access structure's member
 

"Keith Thompson" <kst-u@mib.org> wrote in message
news:lnipnnpcsx.fsf@nuthaus.mib.org...
[skip]
> Since the initial value of foo.a is 0 (that's new information),
> "foo1.a++" will have the side effect of incrementing foo.a, setting it
> to 1. But the result of the postfix "++" operator is the value of the
> operand *before* it's incremented, so the value printed will be 0. (If
> that weren't the case, there would be no point in having prefix and
> postfix versions of "++"; they'd both do the same thing.)
>


Thanks a lot for claryfing me the essence of C language once again !

Mark




All times are GMT. The time now is 08:55 AM.

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