Declaring variables in "case" blocks?

Discussion in 'C Programming' started by Robbie Hatley, Jul 31, 2007.

  1. Greetings, group. I just found a weird problem in a program where
    a variable declared in a {block} after a "case" keyword was being
    treated as having value 0 even though its actual value should
    have been something else. An extremely stripped-down version:

    int Function (int something)
    {
    switch(something)
    {
    case WHATEVER:
    {
    int DumVar = 72;
    // Some code uses DumVar. It seems to see the value
    // of DumVar as being 0 ! What the heck???
    break;
    }
    }
    }

    Is there anything wrong with that? Does it violate some rule
    of C that I'm missing? It's almost as if the first time I
    try to read Dumvar in the code, it's being redeclared (as int),
    redefined, and reinitialized to 0.

    When I moved the declaration of DumVar up to the top of the
    function, it now works correctly:

    int Function (int something-)
    {
    int DumVar = 72;
    switch(something)
    {
    case WHATEVER:
    {
    // Code here now sees the value of DumVar as being 72
    break;
    }
    }
    }

    So am I just missing something, or is my compiler buggy?

    (I'm using National Instruments "CVI" compiler for this;
    I haven't tested this on a more common compiler such as GCC.)

    --
    Cheers,
    Robbie Hatley
    lone wolf aatt well dott com
    triple-dubya dott Tustin Free Zone dott org
     
    Robbie Hatley, Jul 31, 2007
    #1
    1. Advertising

  2. "Robbie Hatley" <> writes:
    > Greetings, group. I just found a weird problem in a program where
    > a variable declared in a {block} after a "case" keyword was being
    > treated as having value 0 even though its actual value should
    > have been something else. An extremely stripped-down version:
    >
    > int Function (int something)
    > {
    > switch(something)
    > {
    > case WHATEVER:
    > {
    > int DumVar = 72;
    > // Some code uses DumVar. It seems to see the value
    > // of DumVar as being 0 ! What the heck???
    > break;
    > }
    > }
    > }


    I think you've stripped down your code so far that you've eliminated
    the error. The above is valid, and code that refers to DumVar will
    see its value as 72. You'd have been better off posting a small
    compilable program, so you could confirm that the problem is still
    there.

    But here's an example that illustrates the problem you're having:

    #include <stdio.h>
    int main(void)
    {
    int x = 42;
    switch(x) {
    int DumVar = 72;
    case 42:
    printf("ok, x = %d, DumVar = %d\n", x, DumVar);
    break;
    default:
    printf("Huh?\n");
    break;
    }
    return 0;
    }

    The output I get is:

    ok, x = 42, DumVar = 1628438944

    after a compiler warning:

    c.c:6: warning: unreachable code at beginning of switch statement

    The problem is that control jumps directly from the 'switch' to the
    appropriate 'case' label, in this case to 'case 42:'. After that,
    DumVar is visible, but you've skipped over its initialization.

    You can safely declare variables within a block following a case
    label, but not within a block that's the entire body of the switch
    statement.

    For more fun with switch statements, see question 20.35 in the
    comp.lang.c FAQ, <http://www.c-faq.com/> (Duff's Device).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jul 31, 2007
    #2
    1. Advertising

  3. "Keith Thompson" <> wrote:

    > "Robbie Hatley" <> writes:
    > > Greetings, group. I just found a weird problem in a program where
    > > a variable declared in a {block} after a "case" keyword was being
    > > treated as having value 0 even though its actual value should
    > > have been something else. An extremely stripped-down version:
    > >
    > > int Function (int something)
    > > {
    > > switch(something)
    > > {
    > > case WHATEVER:
    > > {
    > > int DumVar = 72;
    > > // Some code uses DumVar. It seems to see the value
    > > // of DumVar as being 0 ! What the heck???
    > > break;
    > > }
    > > }
    > > }

    >
    > I think you've stripped down your code so far that you've eliminated
    > the error.


    Maybe so.

    > The above is valid


    That's what I was wondering about. Thanks.

    > and code that refers to DumVar will see its value as 72.


    Theoretically, yes.

    In practice (in my program, with my compiler), I was seeing 0,
    which is why I was so puzzled.

    > You'd have been better off posting a small compilable program,
    > so you could confirm that the problem is still there.


    I (mostly) did. If you #define WHATEVER, then call Function()
    from main(), it will compile and run.

    Hmmm... let me try that.

    Ok, I just compiled and ran my stripped-down version here,
    with a sprintf() of DumVar to a char buffer, and printed the buffer
    in a popup message box. It displays as "72". Oops. Problem went
    away. Weird.

    I'm truly perplexed. I'll have to try to reproduce this bizarre
    bug again.

    > But here's an example that illustrates the problem you're having:
    >
    > #include <stdio.h>
    > int main(void)
    > {
    > int x = 42;
    > switch(x) {
    > int DumVar = 72;
    > case 42:
    > printf("ok, x = %d, DumVar = %d\n", x, DumVar);
    > break;
    > default:
    > printf("Huh?\n");
    > break;
    > }
    > return 0;
    > }


    Nice try, but that's not my problem. I was careful to put
    the variable declaration at the top of a {block}, just under a
    CASE label, like so:

    #include <stdio.h>
    int main(void)
    {
    int x = 42;
    switch(x) {
    case 42:
    {
    int DumVar = 72;
    printf("ok, x = %d, DumVar = %d\n", x, DumVar);
    break;
    }
    default:
    printf("Huh?\n");
    break;
    }
    return 0;
    }

    and I was getting "DumVar = 0". Definitely wasn't a large
    value (uninitialized RAM garbage) as you're getting here:

    > The output I get is:
    >
    > ok, x = 42, DumVar = 1628438944
    >
    > after a compiler warning:
    >
    > c.c:6: warning: unreachable code at beginning of switch statement
    >
    > The problem is that control jumps directly from the 'switch' to the
    > appropriate 'case' label, in this case to 'case 42:'. After that,
    > DumVar is visible, but you've skipped over its initialization.


    Yep! I've seen that one bite even highly-experienced co-workers.
    Since your declaration is never executed, your compiler declares
    the variable as int for you, allocates some memory, but doesn't
    initialize it to anything. So it's value could be anything from
    -(2^31) to +(2^31)-1. (Assuming 32-bit int, 2's comp. rep.)

    > You can safely declare variables within a block following a case
    > label, but not within a block that's the entire body of the switch
    > statement.


    Well, you could... but the code will never execute.

    > For more fun with switch statements, see question 20.35 in the
    > comp.lang.c FAQ, <http://www.c-faq.com/> (Duff's Device).


    Whoa! It's actually legal to jump into the middle of a do loop
    that way?! Cool machine!

    --
    Cheers,
    Robbie Hatley
    lone wolf aatt well dott com
    triple-dubya dott Tustin Free Zone dott org
     
    Robbie Hatley, Jul 31, 2007
    #3
  4. Robbie Hatley

    Flash Gordon Guest

    Robbie Hatley wrote, On 31/07/07 21:20:
    > "Keith Thompson" <> wrote:
    >
    >> "Robbie Hatley" <> writes:


    <snip>

    >> You'd have been better off posting a small compilable program,
    >> so you could confirm that the problem is still there.

    >
    > I (mostly) did. If you #define WHATEVER, then call Function()
    > from main(), it will compile and run.
    >
    > Hmmm... let me try that.
    >
    > Ok, I just compiled and ran my stripped-down version here,
    > with a sprintf() of DumVar to a char buffer, and printed the buffer
    > in a popup message box. It displays as "72". Oops. Problem went
    > away. Weird.


    <snip>

    This is why you should always reduce your code to a small compilable
    example that exhibits the problem (obviously, if the problem is it not
    compiling then it does not need to be compilable!). There is no point
    other people trying to debug a problem in code that does not exhibit the
    problem.
    --
    Flash Gordon
     
    Flash Gordon, Jul 31, 2007
    #4
  5. "Robbie Hatley" <> writes:
    > "Keith Thompson" <> wrote:
    >> "Robbie Hatley" <> writes:
    >> > Greetings, group. I just found a weird problem in a program where
    >> > a variable declared in a {block} after a "case" keyword was being
    >> > treated as having value 0 even though its actual value should
    >> > have been something else. An extremely stripped-down version:
    >> >
    >> > int Function (int something)
    >> > {
    >> > switch(something)
    >> > {
    >> > case WHATEVER:
    >> > {
    >> > int DumVar = 72;
    >> > // Some code uses DumVar. It seems to see the value
    >> > // of DumVar as being 0 ! What the heck???
    >> > break;
    >> > }
    >> > }
    >> > }

    >>
    >> I think you've stripped down your code so far that you've eliminated
    >> the error.

    >
    > Maybe so.
    >
    >> The above is valid

    >
    > That's what I was wondering about. Thanks.
    >
    >> and code that refers to DumVar will see its value as 72.

    >
    > Theoretically, yes.
    >
    > In practice (in my program, with my compiler), I was seeing 0,
    > which is why I was so puzzled.


    You weren't seeing 0 with the code that you posted. Without seeing
    code that does display 0, I can't make any definitive comments.

    >> You'd have been better off posting a small compilable program,
    >> so you could confirm that the problem is still there.

    >
    > I (mostly) did. If you #define WHATEVER, then call Function()
    > from main(), it will compile and run.
    >
    > Hmmm... let me try that.
    >
    > Ok, I just compiled and ran my stripped-down version here,
    > with a sprintf() of DumVar to a char buffer, and printed the buffer
    > in a popup message box. It displays as "72". Oops. Problem went
    > away. Weird.


    There's nothing weird about it. The code you posted doesn't exhibit
    the error.

    You need to create your own complete stripped-down program, and run it
    yourself to exhibit the error, *before* you post it here.

    > I'm truly perplexed. I'll have to try to reproduce this bizarre
    > bug again.


    Please do.

    Do you still have the original code that exhibited the problem? It's
    probably too big to post here, but be sure you save a copy of it so
    you can use it as a basis for creating something that you can post.

    >> But here's an example that illustrates the problem you're having:
    >>
    >> #include <stdio.h>
    >> int main(void)
    >> {
    >> int x = 42;
    >> switch(x) {
    >> int DumVar = 72;
    >> case 42:
    >> printf("ok, x = %d, DumVar = %d\n", x, DumVar);
    >> break;
    >> default:
    >> printf("Huh?\n");
    >> break;
    >> }
    >> return 0;
    >> }

    >
    > Nice try, but that's not my problem. I was careful to put
    > the variable declaration at the top of a {block}, just under a
    > CASE label, like so:
    >
    > #include <stdio.h>
    > int main(void)
    > {
    > int x = 42;
    > switch(x) {
    > case 42:
    > {
    > int DumVar = 72;
    > printf("ok, x = %d, DumVar = %d\n", x, DumVar);
    > break;
    > }
    > default:
    > printf("Huh?\n");
    > break;
    > }
    > return 0;
    > }
    >
    > and I was getting "DumVar = 0". Definitely wasn't a large
    > value (uninitialized RAM garbage) as you're getting here:


    Most likely you're mistaken, or perhaps you're having some other
    problem that's not related to the switch statement.

    >> The output I get is:
    >>
    >> ok, x = 42, DumVar = 1628438944
    >>
    >> after a compiler warning:
    >>
    >> c.c:6: warning: unreachable code at beginning of switch statement
    >>
    >> The problem is that control jumps directly from the 'switch' to the
    >> appropriate 'case' label, in this case to 'case 42:'. After that,
    >> DumVar is visible, but you've skipped over its initialization.

    >
    > Yep! I've seen that one bite even highly-experienced co-workers.
    > Since your declaration is never executed, your compiler declares
    > the variable as int for you, allocates some memory, but doesn't
    > initialize it to anything. So it's value could be anything from
    > -(2^31) to +(2^31)-1. (Assuming 32-bit int, 2's comp. rep.)
    >
    >> You can safely declare variables within a block following a case
    >> label, but not within a block that's the entire body of the switch
    >> statement.

    >
    > Well, you could... but the code will never execute.


    The initializer, if any, will be skipped -- but the variable will
    exist. This is not a good idea, though, since you can always declare
    it in an outer scope.

    >> For more fun with switch statements, see question 20.35 in the
    >> comp.lang.c FAQ, <http://www.c-faq.com/> (Duff's Device).

    >
    > Whoa! It's actually legal to jump into the middle of a do loop
    > that way?! Cool machine!


    It's the language, not any particular machine. Duff's Device is legal
    and portable (though there's some controversy about this).

    A switch statement is a lower-level construct than it appears to be.
    It's really nothing more than a computed goto within a single
    statement (which can be a block). The error of skipping an initializer
    in a switch statement is really no different than this:

    #include <stdio.h>
    int main(void)
    {
    goto LABEL;
    {
    int x = 42;
    LABEL:
    printf("x = %d\n", x);
    }
    return 0;
    }

    As for the problem you're having in your code, no offense, but I don't
    believe that it's as you describe it. If you can post an actual
    program that exhibits the problem (by "actual program" I mean
    something that anyone else can copy-and-paste, compile, link, and
    execute, with no modifications), then we'll be glad to look at it.
    But all we've seen so far is code that doesn't exhibit the problem,
    and code that does exhibit a problem but for reasons different from
    what you describe.

    It's possible that you've run across either an obscure corner of the
    language that I'm not thinking of, or a compiler bug, but that's not
    the way to bet.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jul 31, 2007
    #5
  6. "Keith Thompson" <> wrote:

    > As for the problem you're having in your code, no offense,


    None taken. :)

    > but I don't believe that it's as you describe it.


    I didn't save a copy of the version that had the problem,
    but I did manually reconstruct it by moving the variable
    declarations back into the block under the case label.

    However, the problem did *NOT* recur!

    I suspect now that it was something like this:

    int Func(int x)
    {
    switch (x)
    {
    case 8:
    {
    int DumVar = 72;
    char Blat[51] = {'\0'};
    sprintf(Blat, "DumVar = %d\n", Dumvar); // ERROR
    MessagePopup("!!!", Blat); // prints "DumVar = 0"
    }
    }
    }

    See the problem? It's on the line marked "ERROR". It's
    almost invisible. Hint: has to do with case.

    :)

    I'm about 80% certain now that something like that was the
    problem. I can never be totally sure what happened, though.

    Next time some bizarre bug like this happens, I'll
    be sure to save a zip snapshot of source (my poor-man's
    version of version control) before making any changes.
    That way, I can post a stripped-down, compilable program
    that actually does exhibit the bug.

    Anyway, thanks for your help.

    --
    Cheers,
    Robbie Hatley
    lone wolf aatt well dott com
    triple-dubya dott Tustin Free Zone dott org
     
    Robbie Hatley, Jul 31, 2007
    #6
  7. "Robbie Hatley" <> writes:
    [...]
    > I suspect now that it was something like this:
    >
    > int Func(int x)
    > {
    > switch (x)
    > {
    > case 8:
    > {
    > int DumVar = 72;
    > char Blat[51] = {'\0'};
    > sprintf(Blat, "DumVar = %d\n", Dumvar); // ERROR
    > MessagePopup("!!!", Blat); // prints "DumVar = 0"
    > }
    > }
    > }
    >
    > See the problem? It's on the line marked "ERROR". It's
    > almost invisible. Hint: has to do with case.


    Got it. So you had a local variable named 'DumVar', and a variable in
    an outer scope named 'Dumvar'? I assume you didn't use those names in
    your actual code, but you might find that a more consistent naming
    convention will help you avoid such problems in the future.

    [...]

    > Next time some bizarre bug like this happens, I'll
    > be sure to save a zip snapshot of source (my poor-man's
    > version of version control) before making any changes.
    > That way, I can post a stripped-down, compilable program
    > that actually does exhibit the bug.


    <OT>
    Consider using an actual version control system. There are several
    free ones out there, and they more than pay for themselves. (I use
    RCS and CVS myself.)
    </OT>

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Aug 1, 2007
    #7
  8. Robbie Hatley

    Army1987 Guest

    On Tue, 31 Jul 2007 22:49:30 +0000, Robbie Hatley wrote:

    > I suspect now that it was something like this:
    >
    > int Func(int x)
    > {
    > switch (x)
    > {
    > case 8:
    > {
    > int DumVar = 72;
    > char Blat[51] = {'\0'};
    > sprintf(Blat, "DumVar = %d\n", Dumvar); // ERROR
    > MessagePopup("!!!", Blat); // prints "DumVar = 0"
    > }
    > }
    > }
    >
    > See the problem? It's on the line marked "ERROR". It's
    > almost invisible. Hint: has to do with case.

    I wouldn't expect it to compile at all, unless there is a Dumvar
    with a small v declared in an outer scope.
    (And do they claim that CamelCase is better than dum_var because
    you could unintentionally spell the latter with a wrong number of
    underscores? Hum...)
    --
    Army1987 (Replace "NOSPAM" with "email")
    "Never attribute to malice that which can be adequately explained
    by stupidity." -- R. J. Hanlon (?)
     
    Army1987, Aug 1, 2007
    #8
  9. Robbie Hatley

    Don Bruder Guest

    In article <_%Ori.207881$>,
    "Robbie Hatley" <> wrote:

    > "Keith Thompson" <> wrote:
    >
    > > As for the problem you're having in your code, no offense,

    >
    > None taken. :)
    >
    > > but I don't believe that it's as you describe it.

    >
    > I didn't save a copy of the version that had the problem,
    > but I did manually reconstruct it by moving the variable
    > declarations back into the block under the case label.
    >
    > However, the problem did *NOT* recur!
    >
    > I suspect now that it was something like this:
    >
    > int Func(int x)
    > {
    > switch (x)
    > {
    > case 8:
    > {
    > int DumVar = 72;
    > char Blat[51] = {'\0'};
    > sprintf(Blat, "DumVar = %d\n", Dumvar); // ERROR
    > MessagePopup("!!!", Blat); // prints "DumVar = 0"
    > }
    > }
    > }
    >
    > See the problem? It's on the line marked "ERROR". It's
    > almost invisible. Hint: has to do with case.


    If that's the actual problem, you would have (Or at least SHOULD have)
    gotten an "undefined identifier: Dumvar" type of error from the
    compiler, since, syntactically, that's exactly what you've got going on.

    --
    Don Bruder - - If your "From:" address isn't on my whitelist,
    or the subject of the message doesn't contain the exact text "PopperAndShadow"
    somewhere, any message sent to this address will go in the garbage without my
    ever knowing it arrived. Sorry... <http://www.sonic.net/~dakidd> for more info
     
    Don Bruder, Aug 1, 2007
    #9
  10. Robbie Hatley

    David Mathog Guest

    Robbie Hatley wrote:
    > I didn't save a copy of the version that had the problem,
    > but I did manually reconstruct it by moving the variable
    > declarations back into the block under the case label.
    >
    > However, the problem did *NOT* recur!


    Use valgrind or another memory access checker on problems
    like this. One reason DumVar could have the wrong value
    is an invalid memory access stomping on it. Putting in print
    statements sometimes moves code around and "fixes" that sort
    of problem, but not really of course.

    >
    > I suspect now that it was something like this:


    Didn't you keep the broken version of the program???

    > sprintf(Blat, "DumVar = %d\n", Dumvar); // ERROR


    That should have thrown a compiler error, unless Dumvar was
    declared elsewhere. Using both DumVar and Dumvar in the same function
    would have been, well, "Dum"!

    Regards,

    David Mathog
     
    David Mathog, Aug 1, 2007
    #10
    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. Mortal Wombat
    Replies:
    3
    Views:
    6,838
    Mortal Wombat
    Aug 7, 2003
  2. Arjen
    Replies:
    3
    Views:
    447
    Scott Allen
    Feb 27, 2005
  3. matt
    Replies:
    1
    Views:
    272
    George Ogata
    Aug 6, 2004
  4. Steven Taylor
    Replies:
    9
    Views:
    256
    Brian Candler
    Apr 27, 2009
  5. kernus
    Replies:
    2
    Views:
    95
Loading...

Share This Page