macro to access structure's member

M

Mark

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
 
F

Fred

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?
 
M

Mark

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.
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)++.
 
M

Morris Keesan

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.
 
K

Keith Thompson

Mark said:
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.
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
?






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++);
 
F

Fred

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


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
?


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.
 
K

Keith Thompson

Morris Keesan said:
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.)
 
N

Nick Keighley

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

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...
 
M

Mark

[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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top