label inside for-loop

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Capstar

    #1

    label inside for-loop

    Hi NG,

    I'm trying to allocate some resources, in this example a structure, with
    containing a buffer. When a allocation failes, all previous allocations
    need to be freed. When I try to compile it I get the next warning:

    resource-loop.c:38: warning: deprecated use of label at end of compound
    statement

    Is there a better way of doing this?
    Or is this guaranteed to work anyway?

    #include <stdlib.h>
    #include <stdio.h>

    struct foo
    {
    char *bar;
    };

    int main(void)
    {
    int i;
    struct foo* array[6];

    for(i = 0; i < 6; ++i)
    {
    if(!(array[i] = malloc(sizeof *array[i])))
    {
    fprintf(stderr, "Unable to allocate foo%d\n", i);
    goto err_malloc_foo;
    }

    if(!(array[i]->bar = malloc(1024)))
    {
    fprintf(stderr, "Unable to allocate bar%d\n", i);
    goto err_malloc_bar;
    }
    }

    return EXIT_SUCCESS;

    for(; i >= 0; --i)
    {
    free(array[i]->bar);
    err_malloc_bar:

    free(array[i]);
    err_malloc_foo:
    }

    return EXIT_FAILURE;
    }


    Mark

    --
    <<Remove the del for email>>

  • Capstar

    #2
    Re: label inside for-loop

    Capstar wrote:[color=blue]
    > Hi NG,
    >
    > I'm trying to allocate some resources, in this example a structure, with
    > containing a buffer. When a allocation failes, all previous allocations
    > need to be freed. When I try to compile it I get the next warning:
    >
    > resource-loop.c:38: warning: deprecated use of label at end of compound
    > statement
    >
    > Is there a better way of doing this?
    > Or is this guaranteed to work anyway?
    >
    > #include <stdlib.h>
    > #include <stdio.h>
    >
    > struct foo
    > {
    > char *bar;
    > };
    >
    > int main(void)
    > {
    > int i;
    > struct foo* array[6];
    >
    > for(i = 0; i < 6; ++i)
    > {
    > if(!(array[i] = malloc(sizeof *array[i])))
    > {
    > fprintf(stderr, "Unable to allocate foo%d\n", i);
    > goto err_malloc_foo;
    > }
    >
    > if(!(array[i]->bar = malloc(1024)))
    > {
    > fprintf(stderr, "Unable to allocate bar%d\n", i);
    > goto err_malloc_bar;
    > }
    > }
    >
    > return EXIT_SUCCESS;
    >
    > for(; i >= 0; --i)
    > {
    > free(array[i]->bar);
    > err_malloc_bar:
    >
    > free(array[i]);
    > err_malloc_foo:
    > }
    >
    > return EXIT_FAILURE;
    > }
    >
    >
    > Mark
    >[/color]

    Ok, I just thought of another way of doing the last piece:

    return EXIT_SUCCESS;

    while(i >= 0)
    {
    free(array[i]->bar);
    err_malloc_bar:

    free(array[i]);
    err_malloc_foo:

    --i;
    }

    return EXIT_FAILURE;

    The warning is gone now, which makes sence because the label is not at
    the end of a compound statement anymore. But why does this make any
    difference? It seems to me that functionally it didn't change at all.

    Or am I missing something here?

    Mark

    --
    <<Remove the del for email>>

    Comment

    • Harti Brandt

      #3
      Re: label inside for-loop

      On Tue, 8 Jun 2004, Capstar wrote:

      C>Capstar wrote:
      C>> Hi NG,
      C>>
      C>> I'm trying to allocate some resources, in this example a structure, with
      C>> containing a buffer. When a allocation failes, all previous allocations need
      C>> to be freed. When I try to compile it I get the next warning:
      C>>
      C>> resource-loop.c:38: warning: deprecated use of label at end of compound
      C>> statement
      C>>
      C>> Is there a better way of doing this?
      C>> Or is this guaranteed to work anyway?
      C>>
      C>> #include <stdlib.h>
      C>> #include <stdio.h>
      C>>
      C>> struct foo
      C>> {
      C>> char *bar;
      C>> };
      C>>
      C>> int main(void)
      C>> {
      C>> int i;
      C>> struct foo* array[6];
      C>>
      C>> for(i = 0; i < 6; ++i)
      C>> {
      C>> if(!(array[i] = malloc(sizeof *array[i])))
      C>> {
      C>> fprintf(stderr, "Unable to allocate foo%d\n", i);
      C>> goto err_malloc_foo;
      C>> }
      C>>
      C>> if(!(array[i]->bar = malloc(1024)))
      C>> {
      C>> fprintf(stderr, "Unable to allocate bar%d\n", i);
      C>> goto err_malloc_bar;
      C>> }
      C>> }
      C>>
      C>> return EXIT_SUCCESS;
      C>>
      C>> for(; i >= 0; --i)
      C>> {
      C>> free(array[i]->bar);
      C>> err_malloc_bar:
      C>>
      C>> free(array[i]);
      C>> err_malloc_foo:
      C>> }
      C>>
      C>> return EXIT_FAILURE;
      C>> }
      C>>
      C>>
      C>> Mark
      C>>
      C>
      C>Ok, I just thought of another way of doing the last piece:
      C>
      C> return EXIT_SUCCESS;
      C>
      C> while(i >= 0)
      C> {
      C> free(array[i]->bar);
      C>err_malloc_ba r:
      C>
      C> free(array[i]);
      C>err_malloc_fo o:
      C>
      C> --i;
      C> }
      C>
      C> return EXIT_FAILURE;
      C>
      C>The warning is gone now, which makes sence because the label is not at the end
      C>of a compound statement anymore. But why does this make any difference? It
      C>seems to me that functionally it didn't change at all.
      C>
      C>Or am I missing something here?

      A label always stands before a statement. If you need a label at the end
      of a compound just put a null-statement after the label:

      foo: ;

      harti

      Comment

      • boa

        #4
        Re: label inside for-loop

        Capstar wrote:[color=blue]
        > Capstar wrote:
        >[color=green]
        >> Hi NG,
        >>
        >> I'm trying to allocate some resources, in this example a structure,
        >> with containing a buffer. When a allocation failes, all previous
        >> allocations need to be freed. When I try to compile it I get the next
        >> warning:
        >>
        >> resource-loop.c:38: warning: deprecated use of label at end of
        >> compound statement
        >>
        >> Is there a better way of doing this?[/color][/color]

        Maybe, how about this version? It has no goto's and has fewer calls to
        malloc, hopefully leading to faster code and less fragmented memory.

        #include <stdlib.h>
        #include <stdio.h>

        struct foo {
        char *bar;
        };

        #define NELEM 6

        int main(void)
        {
        int i;
        struct foo* array;

        if( (array = malloc(sizeof *array * NELEM)) == NULL)
        return EXIT_FAILURE;

        for(i = 0; i < NELEM; i++) {
        if( (array[i].bar = malloc(1024)) == NULL) {
        while(--i >= 0)
        free(array[i].bar);
        free(array);
        return EXIT_FAILURE;
        }
        }

        return EXIT_SUCCESS;
        }


        HTH,
        boa
        [snip]

        Comment

        • Capstar

          #5
          Re: label inside for-loop

          boa wrote:[color=blue]
          > Capstar wrote:
          >[color=green]
          >> Capstar wrote:
          >>[color=darkred]
          >>> Hi NG,
          >>>
          >>> I'm trying to allocate some resources, in this example a structure,
          >>> with containing a buffer. When a allocation failes, all previous
          >>> allocations need to be freed. When I try to compile it I get the next
          >>> warning:
          >>>
          >>> resource-loop.c:38: warning: deprecated use of label at end of
          >>> compound statement
          >>>
          >>> Is there a better way of doing this?[/color][/color]
          >
          >
          > Maybe, how about this version? It has no goto's and has fewer calls to
          > malloc, hopefully leading to faster code and less fragmented memory.
          >
          > #include <stdlib.h>
          > #include <stdio.h>
          >
          > struct foo {
          > char *bar;
          > };
          >
          > #define NELEM 6
          >
          > int main(void)
          > {
          > int i;
          > struct foo* array;
          >
          > if( (array = malloc(sizeof *array * NELEM)) == NULL)
          > return EXIT_FAILURE;
          >
          > for(i = 0; i < NELEM; i++) {
          > if( (array[i].bar = malloc(1024)) == NULL) {
          > while(--i >= 0)
          > free(array[i].bar);
          > free(array);
          > return EXIT_FAILURE;
          > }
          > }
          >
          > return EXIT_SUCCESS;
          > }
          >[/color]

          This is about how I would normally do this, but this was just some
          example code. The actual code is part of the initialisation code for a
          device driver. So there are lots of calls, which can fail. And if one
          fails all previous calls that allocate or register stuff need to be
          undone. That can offcourse be done without any goto's but, but That
          would mean lots of nested if-else statements, and make my code complete
          unreadable. This loop thing is ment for requesting some pci space and
          mapping it to virtual memory space. In my previous version I just copied
          the code 6 times. So this was actually an effort to clean things up a bit.

          But thanks for your input anyway.

          Mark
          --
          <<Remove the del for email>>

          Comment

          • Capstar

            #6
            Re: label inside for-loop

            Harti Brandt wrote:[color=blue]
            > On Tue, 8 Jun 2004, Capstar wrote:
            >
            > C>Capstar wrote:
            > C>> Hi NG,
            > C>>
            > C>> I'm trying to allocate some resources, in this example a structure, with
            > C>> containing a buffer. When a allocation failes, all previous allocations need
            > C>> to be freed. When I try to compile it I get the next warning:
            > C>>
            > C>> resource-loop.c:38: warning: deprecated use of label at end of compound
            > C>> statement
            > C>>
            > C>> Is there a better way of doing this?
            > C>> Or is this guaranteed to work anyway?
            > C>>
            > C>> #include <stdlib.h>
            > C>> #include <stdio.h>
            > C>>
            > C>> struct foo
            > C>> {
            > C>> char *bar;
            > C>> };
            > C>>
            > C>> int main(void)
            > C>> {
            > C>> int i;
            > C>> struct foo* array[6];
            > C>>
            > C>> for(i = 0; i < 6; ++i)
            > C>> {
            > C>> if(!(array[i] = malloc(sizeof *array[i])))
            > C>> {
            > C>> fprintf(stderr, "Unable to allocate foo%d\n", i);
            > C>> goto err_malloc_foo;
            > C>> }
            > C>>
            > C>> if(!(array[i]->bar = malloc(1024)))
            > C>> {
            > C>> fprintf(stderr, "Unable to allocate bar%d\n", i);
            > C>> goto err_malloc_bar;
            > C>> }
            > C>> }
            > C>>
            > C>> return EXIT_SUCCESS;
            > C>>
            > C>> for(; i >= 0; --i)
            > C>> {
            > C>> free(array[i]->bar);
            > C>> err_malloc_bar:
            > C>>
            > C>> free(array[i]);
            > C>> err_malloc_foo:
            > C>> }
            > C>>
            > C>> return EXIT_FAILURE;
            > C>> }
            > C>>
            > C>>
            > C>> Mark
            > C>>
            > C>
            > C>Ok, I just thought of another way of doing the last piece:
            > C>
            > C> return EXIT_SUCCESS;
            > C>
            > C> while(i >= 0)
            > C> {
            > C> free(array[i]->bar);
            > C>err_malloc_ba r:
            > C>
            > C> free(array[i]);
            > C>err_malloc_fo o:
            > C>
            > C> --i;
            > C> }
            > C>
            > C> return EXIT_FAILURE;
            > C>
            > C>The warning is gone now, which makes sence because the label is not at the end
            > C>of a compound statement anymore. But why does this make any difference? It
            > C>seems to me that functionally it didn't change at all.
            > C>
            > C>Or am I missing something here?
            >
            > A label always stands before a statement. If you need a label at the end
            > of a compound just put a null-statement after the label:
            >
            > foo: ;
            >[/color]

            Thanks, that did the trick.

            After opening a book after reading this, I found out that a goto points
            to a 'labelled statement', and not to just a 'label' as I used to think.

            Never to old to learn
            --
            <<Remove the del for email>>

            Comment

            • Darrell Grainger

              #7
              Re: label inside for-loop

              On Tue, 8 Jun 2004, Capstar wrote:
              [color=blue]
              > Hi NG,
              >
              > I'm trying to allocate some resources, in this example a structure, with
              > containing a buffer. When a allocation failes, all previous allocations
              > need to be freed. When I try to compile it I get the next warning:
              >
              > resource-loop.c:38: warning: deprecated use of label at end of compound
              > statement
              >
              > Is there a better way of doing this?[/color]

              Allocate one large block of memory and initialize the pointers so they
              point into that one large block. One call to malloc, one call to free.
              [color=blue]
              > Or is this guaranteed to work anyway?
              >
              > #include <stdlib.h>
              > #include <stdio.h>
              >
              > struct foo
              > {
              > char *bar;
              > };
              >
              > int main(void)
              > {
              > int i;
              > struct foo* array[6];
              >
              > for(i = 0; i < 6; ++i)
              > {
              > if(!(array[i] = malloc(sizeof *array[i])))
              > {
              > fprintf(stderr, "Unable to allocate foo%d\n", i);
              > goto err_malloc_foo;
              > }
              >
              > if(!(array[i]->bar = malloc(1024)))
              > {
              > fprintf(stderr, "Unable to allocate bar%d\n", i);
              > goto err_malloc_bar;
              > }
              > }
              >
              > return EXIT_SUCCESS;
              >
              > for(; i >= 0; --i)
              > {
              > free(array[i]->bar);
              > err_malloc_bar:
              >
              > free(array[i]);
              > err_malloc_foo:
              > }
              >
              > return EXIT_FAILURE;
              > }
              >
              >
              > Mark
              >
              > --
              > <<Remove the del for email>>
              >
              >[/color]

              --
              Send e-mail to: darrell at cs dot toronto dot edu
              Don't send e-mail to vice.president@ whitehouse.gov

              Comment

              • SM Ryan

                #8
                Re: label inside for-loop

                # resource-loop.c:38: warning: deprecated use of label at end of compound
                # statement

                Use an empty statement.

                # free(array[i]);
                # err_malloc_foo:
                # }

                free(array[i]);
                err_malloc_foo:
                ;
                }

                --
                SM Ryan http://www.rawbw.com/~wyrmwif/
                Title does not dictate behaviour.

                Comment

                • Mark F. Haigh

                  #9
                  Re: label inside for-loop

                  Capstar <news@deleg.hom eip.net> wrote in message news:<ca3vu4$rb h$1@news.tudelf t.nl>...[color=blue]
                  > Hi NG,
                  >
                  > I'm trying to allocate some resources, in this example a structure, with
                  > containing a buffer. When a allocation failes, all previous allocations
                  > need to be freed. When I try to compile it I get the next warning:
                  >
                  > resource-loop.c:38: warning: deprecated use of label at end of compound
                  > statement
                  >[/color]

                  Look at the following section in the C99 standard:

                  A.2.3 Statements

                  (6.8.1) labeled-statement:
                  identifier : statement
                  case constant-expression : statement
                  default : statement

                  You'll notice that a label does not stand alone; rather, it's labeling
                  a statement. What's prompting the warning from the compiler is that
                  you're labeling the closing bracket.

                  Instead, simply label an empty statement like:

                  <snip>[color=blue]
                  > for(; i >= 0; --i)
                  > {
                  > free(array[i]->bar);
                  > err_malloc_bar:
                  >
                  > free(array[i]);
                  > err_malloc_foo:[/color]
                  ; /* empty statement */[color=blue]
                  > }
                  >
                  > return EXIT_FAILURE;
                  > }[/color]


                  Mark F. Haigh
                  mfhaigh@sbcglob al.net

                  Comment

                  • Chris Torek

                    #10
                    Re: label inside for-loop

                    In article <news:ca3vu4$rb h$1@news.tudelf t.nl>
                    Capstar <news@deleg.hom eip.net> writes:

                    [ "goto label; ... { ... label: }" produces the complaint ]
                    [color=blue]
                    >resource-loop.c:38: warning: deprecated use of label at end of compound
                    >statement[/color]

                    As others have noted, the immediate fix is to use a null statement.

                    It is worth pointing out that what is "deprecated " here is actually
                    a GNUC extension -- the syntax above has always been invalid in
                    ANSI C. The GCC folks decided to allow it, and have now decided
                    to stop allowing it.

                    For those who want to find one, there is a moral in here about
                    depending on compiler-specific extensions. :-)
                    --
                    In-Real-Life: Chris Torek, Wind River Systems
                    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
                    email: forget about it http://web.torek.net/torek/index.html
                    Reading email is like searching for food in the garbage, thanks to spammers.

                    Comment

                    • josh

                      #11
                      Re: label inside for-loop

                      Capstar wrote:[color=blue]
                      > Hi NG,
                      >
                      > I'm trying to allocate some resources, in this example a structure, with
                      > containing a buffer. When a allocation failes, all previous allocations
                      > need to be freed. When I try to compile it I get the next warning:
                      >
                      > resource-loop.c:38: warning: deprecated use of label at end of compound
                      > statement
                      >
                      > Is there a better way of doing this?
                      > Or is this guaranteed to work anyway?[/color]

                      Since free(NULL) does nothing, you could do:

                      [...][color=blue]
                      >
                      > for(; i >= 0; --i)
                      > {[/color]
                      err_malloc_bar:
                      free(array[i]->bar);

                      err_malloc_foo:
                      free(array[i]);[color=blue]
                      > }
                      >
                      > return EXIT_FAILURE;
                      > }[/color]

                      Alternatively:

                      struct foo
                      {
                      char *bar, *baz;
                      };

                      int main(void)
                      {
                      int i;
                      struct foo* array[6];
                      for (i=0; i<6; ++i)
                      {
                      if (!(array[i] = malloc(sizeof array[i])))
                      break;
                      if (!(array[i].bar = malloc(1024)))
                      break;
                      if (!(array[i].baz = malloc(256)))
                      break;
                      }
                      if (i == 6)
                      return EXIT_SUCCESS;

                      if (!array[i]) --i;
                      for (; i>=0; free(array[i--]))
                      {
                      /* check in the same order as allocation */
                      /* when we hit a NULL, the rest are unallocated */
                      if (!array[i].bar) continue;
                      free(array[i].bar);
                      if (!array[i].baz) continue;
                      free(array[i].baz);
                      }
                      return EXIT_FAILURE;
                      }

                      Or you could have a second variable that you set to 0 at the start of
                      the alloc loop and increment at each step. On failure, do a nasty
                      duff-esque switch/for:

                      int main(void)
                      {
                      int i,fail_step;
                      struct foo* array[6];
                      for (i=0; i<6; ++i)
                      {
                      fail_step = 0;
                      if (!(array[i] = malloc(sizeof array[i])))
                      break;
                      ++fail_step;
                      if (!(array[i].bar = malloc(1024)))
                      break;
                      ++fail_step;
                      if (!(array[i].baz = malloc(256)))
                      break;
                      }
                      if (i == 6)
                      return EXIT_SUCCESS;

                      switch (fail_step)
                      {
                      for (; i>=0; --i)
                      {
                      /* needs to be in reverse of alloc order */
                      case 2: free(array[i].baz]);
                      case 1: free(array[i].bar]);
                      case 0: free(array[i]);
                      }
                      }
                      return EXIT_FAILURE;
                      }

                      but I dunno if that's really any better than goto. (it'd really suck to
                      add a step in the middle...)

                      -josh

                      Comment

                      Working...