Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > macro to access structure's member

Reply
Thread Tools

macro to access structure's member

 
 
Mark
Guest
Posts: n/a
 
      10-17-2011
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


 
Reply With Quote
 
 
 
 
Fred
Guest
Posts: n/a
 
      10-17-2011
On Oct 17, 11:22*am, "Mark" <(E-Mail Removed)> 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


 
Reply With Quote
 
 
 
 
Mark
Guest
Posts: n/a
 
      10-17-2011

"Fred" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
>> 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



 
Reply With Quote
 
Morris Keesan
Guest
Posts: n/a
 
      10-17-2011
On Mon, 17 Oct 2011 16:09:22 -0400, Mark <(E-Mail Removed)>
wrote:

>
> "Fred" <(E-Mail Removed)> 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 -- http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-17-2011
"Mark" <(E-Mail Removed)> writes:
> "Fred" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>>> 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) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Fred
Guest
Posts: n/a
 
      10-17-2011
On Oct 17, 1:09*pm, "Mark" <(E-Mail Removed)> wrote:
> "Fred" <(E-Mail Removed)> wrote in message
>
> news:(E-Mail Removed)...
>
> >> 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
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      10-17-2011
"Morris Keesan" <(E-Mail Removed)> 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) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      10-18-2011
On Oct 17, 9:46*pm, Fred <(E-Mail Removed)> wrote:
> On Oct 17, 1:09*pm, "Mark" <(E-Mail Removed)> wrote:
> > "Fred" <(E-Mail Removed)> wrote in message
> >news:(E-Mail Removed)....



> > >> 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...
 
Reply With Quote
 
Mark
Guest
Posts: n/a
 
      10-19-2011

"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
[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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can a static member function access non-static member? dolphin C++ 3 12-05-2007 12:39 PM
Can Derived class static member access protected member from base class? Siemel Naran C++ 4 01-12-2005 06:46 PM
How would I use qsort to sort a struct with a char* member and a long member - I want to sort in order of the long member Angus Comber C Programming 7 02-05-2004 06:41 PM
Struct member access with macro dam_fool_2003@yahoo.com C Programming 5 09-30-2003 02:33 AM
how do I access a member of vector when this vector is a member of a class ding feng C++ 8 07-02-2003 08:06 AM



Advertisments