A block statement is any list of statements that is enclosed between a left curly brace, '{', and a right curly brace, '}', including a null list, i.e.:
{ } /* null list block statement */
At the beginning of every block statement, between the left curly brace, '{', and the statement list, one can optionally have a list of declarations which define local data objects or declare functions, e.g.:
{ int x, func(void); statement_list; }
Any data so defined is local data, local to the containing function and with a scope only within the curly braces.
Block statements can be nested to any limit. Note that a function body always contains one single block statement with the optional declarations followed by the optional statement list.
It is possible to use a goto statement to jump into or out of a block. If there are any non static (i.e. auto) storage class data declarations, then those data items will be created on the stack upon jumping into or normally entering the block; and will be destroyed (popped off the stack) when jumping out of or flowing through the bottom of the block.
Thus local variables in a block which is not a function body can add a lot of hidden overhead in stack manipulation. This overhead can be eliminated by declaring all local variables at the outermost possible block - usually that of the function body itself.