2

Within scope, will all declarations happen at the beginning of a function after compilation (in C)? The following examples shows a bit better what I am wondering. If something goes wrong with "ptr1", can I assume that ptr2 has been initialized to NULL?

int main()
{
  int ret = 0;

  void * ptr1 = NULL;
  if (ret = do_ptr_work(ptr1))
    goto done;

  void * ptr2 = NULL;
  if (ret = do_ptr_work(ptr2))
    goto done;

done:
  if (ptr1) {
    free(ptr1);
    ptr1 = NULL;
  }
  if (ptr2) {
    free(ptr2);
    ptr2 = NULL;
  }

  return ret;
}

Thanks, Chenz

Crazy Chenz
  • 12,650
  • 12
  • 50
  • 62
  • 2
    Possible duplicate: http://stackoverflow.com/questions/2821663/c99-goto-past-initialization – payne Feb 02 '11 at 12:52
  • 1
    Why do you have to use goto for this? And if you want to ensure that both are initialised, isn't it easy enough to move both declarations to the top of the function? – pjc50 Feb 02 '11 at 12:55
  • Agreed.... this is a duplicate... thanks! (Now how do I direct people to the first question?) – Crazy Chenz Feb 02 '11 at 13:18

2 Answers2

3

No. The initialisation is defined to happen when the declaration is reached. If you jump over the initialisation, the variable exists but is uninitialised.

One relevant part of the C standard is §6.2.4:

If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

(Note that this text applies only to objects with automatic storage duration). Another is §6.8:

The initializers of objects that have automatic storage duration, and the variable length array declarators of ordinary identifiers with block scope, are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear.

caf
  • 233,326
  • 40
  • 323
  • 462
0

Personally I'd avoid that approach altogether as it seems to get far too close to undefined behaviour for my liking and it is bound to cause problems, either when you move to a different compiler/platform or just when you confuse the maintenance programmers.

Why not just declare the variables at the start of the scope? Looks neater to my eyes anyway.

int main()
{
  void * ptr1 = NULL;
  void * ptr2 = NULL;
  int ret = 0;

  if (ret = do_ptr_work(ptr1))
    goto done;

  if (ret = do_ptr_work(ptr2))
    goto done;

done:
  if (ptr1) {
    free(ptr1);
    ptr1 = NULL;
  }
  if (ptr2) {
    free(ptr2);
    ptr2 = NULL;
  }

  return ret;
}

Or even just refactor completely to remove the goto?

int main()
{
  void * ptr1 = NULL;
  void * ptr2 = NULL;

  int ret = do_ptr_work(ptr1);

  if (!ret) 
    ret = do_ptr_work(ptr2);

  // Tidy up...
  if (ptr1) {
    free(ptr1);
    ptr1 = NULL;
  }
  if (ptr2) {
    free(ptr2);
    ptr2 = NULL;
  }

  return ret;
}
GrahamS
  • 9,980
  • 9
  • 49
  • 63
  • I'm cool with your first example, but the second encourages really deep functions that are difficult to maintain and track by eye. The goto's are strickly used for exception handling, not program flow, therefore they are OK (IMO.) – Crazy Chenz Feb 02 '11 at 13:17
  • 1
    @Crazy Chenz: I don't really have a religious issue with `goto` being used in that context, but I still avoid them where I can and it didn't seem required here. If that pattern is common in your code then fair enough. Not sure about your comment regarding "really deep functions" though - hasn't my refactoring actually reduced the complexity? (e.g. one less comparison, 6 possible paths through the code instead of 9). – GrahamS Feb 02 '11 at 13:53