macro to access structure's member

Discussion in 'C Programming' started by Mark, Oct 17, 2011.

  1. Mark

    Mark Guest

    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
    Mark, Oct 17, 2011
    #1
    1. Advertising

  2. Mark

    Fred Guest

    On Oct 17, 11:22 am, "Mark" <> 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
    Fred, Oct 17, 2011
    #2
    1. Advertising

  3. Mark

    Mark Guest

    "Fred" <> wrote in message
    news:...
    >> 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
    Mark, Oct 17, 2011
    #3
  4. On Mon, 17 Oct 2011 16:09:22 -0400, Mark <>
    wrote:

    >
    > "Fred" <> 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 --
    Morris Keesan, Oct 17, 2011
    #4
  5. "Mark" <> writes:
    > "Fred" <> wrote in message
    > news:...
    >>> 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) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Oct 17, 2011
    #5
  6. Mark

    Fred Guest

    On Oct 17, 1:09 pm, "Mark" <> wrote:
    > "Fred" <> wrote in message
    >
    > news:...
    >
    > >> 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
    Fred, Oct 17, 2011
    #6
  7. "Morris Keesan" <> 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) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Oct 17, 2011
    #7
  8. On Oct 17, 9:46 pm, Fred <> wrote:
    > On Oct 17, 1:09 pm, "Mark" <> wrote:
    > > "Fred" <> wrote in message
    > >news:....



    > > >> 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...
    Nick Keighley, Oct 18, 2011
    #8
  9. Mark

    Mark Guest

    "Keith Thompson" <> wrote in message
    news:...
    [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
    Mark, Oct 19, 2011
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dead RAM
    Replies:
    20
    Views:
    1,111
    John Harrison
    Jul 14, 2004
  2. D Senthil Kumar

    macro name from macro?

    D Senthil Kumar, Sep 20, 2003, in forum: C Programming
    Replies:
    1
    Views:
    578
    Jack Klein
    Sep 21, 2003
  3. Struct member access with macro

    , Sep 29, 2003, in forum: C Programming
    Replies:
    5
    Views:
    610
    CBFalconer
    Sep 30, 2003
  4. sounak

    to get macro name from macro value

    sounak, Nov 22, 2005, in forum: C Programming
    Replies:
    17
    Views:
    501
    Mark McIntyre
    Nov 22, 2005
  5. Patrick Kowalzick
    Replies:
    5
    Views:
    470
    Patrick Kowalzick
    Mar 14, 2006
Loading...

Share This Page