User: Password:
|
|
Subscribe / Log in / New account

C89 includes blocks you know...

C89 includes blocks you know...

Posted Jun 10, 2008 21:36 UTC (Tue) by ballombe (subscriber, #9523)
Parent article: Implications of pure and constant functions

The Dead Code Elimination optimization can be very helpful to reduce the overhead caused by code written to conform to C89 standard, where you couldn't mix variables (and constant) declarations with executable code. In those sources, you had to declare variables at the top of the function, and then start to check for prerequisites. If you wanted to make it explicit that some variable had to keep its value, by making it constant, you would often have to fill them before the prerequisites could be checked.

Actually C89 only requires to declare variables at the top of a block, and you could nest blocks arbitrarily, so the limitation you mention did not exist, you just had to create a new block:

fun(int n)
{
   int is0 = (n==0);
   if (is0)
     n=1;
   {
      const double z=1/((double) n);

      ....
   }
}
C99 allows to omit the extra braces, but that's about it.


(Log in to post comments)

Omitting extra braces is a boon

Posted Jun 10, 2008 21:56 UTC (Tue) by jreiser (subscriber, #11027) [Link]

C99 allows to omit the extra braces, but that's about it.

Allowing the braces to be omitted is a significant advantage. It's some syntactic sugar that is really worth it. The combination of requiring braces and coding style conventions can cause swift migration towards the right margin. This impedes readability. I favor placing declarations so as to include the smallest possible span of lines; this eases maintenance by clearly delimiting dataflow. If I must surround every new group of declarations with braces, then the code is often two or three indentations farther to the right. Either that, or I "cheat" on the indentation rules, by placing the braces farther to the left so as to keep the same indentation for the statements which use the new variables.

Omitting extra braces is a boon

Posted Jun 11, 2008 7:08 UTC (Wed) by jengelh (subscriber, #33263) [Link]

Allowing mixing of declarations and code the C99/C++ way I consider a disadvantage, because you have to scan the entire function to get to know what variables it will use. And some people write horribly long functions without breaking them up — asterisk comes to mind. Having the code go too far to the right is a sign that you should probably break the function (see CodingStyle).

Omitting extra braces is a boon

Posted Jun 11, 2008 18:43 UTC (Wed) by bronson (subscriber, #4806) [Link]

Doesn't your editor or IDE color the variable declarations?

Omitting extra braces is a boon

Posted Jun 11, 2008 19:11 UTC (Wed) by jengelh (subscriber, #33263) [Link]

That's not the point.

Omitting extra braces is a boon

Posted Jun 12, 2008 0:08 UTC (Thu) by dododge (subscriber, #2870) [Link]

If your point is that people write horrible over-long functions, no argument there. The C89 rules certainly didn't stop them doing it, though, and frankly if I'm dealing with some 1000-line monstrosity of a function I'd rather be able to put the declarations on the same screen as the code using them, so that 1) I don't have to keep skipping back and forth to remember the types, and 2) I don't have to worry about what the 200 lines of code between the start of the function and the spot I'm looking at might have done with those variables.

But the main point, as already stated, is that from a practical standpoint you can't easily make your local variables const unless you either use mixed declarations or futz about with bracing and deep nesting. As someone who marks as much const as I can, and tries to limit scope as much as possible, I do make heavy use of mixed declarations and it's one of the C99 features that would be hardest to give up.

Omitting extra braces is a boon

Posted Jun 12, 2008 13:41 UTC (Thu) by IkeTo (subscriber, #2122) [Link]

> you have to scan the entire function to get to know what variables it will use.

I don't use any IDE other than plain Emacs.  But there is a search function, so the "scan"
that you mentioned is really by the editor program, not by myself.  On the other hand, I don't
find it overly useful to know what variables a function will use.  It is much more useful to
know what the function will do.  Since I don't usually trust comments in code, this is a
difficult task by itself, and it is much easier if there is not a dozen of variables springing
up at the same point of code which are not used for a dozen of lines (and I have to repeatedly
use the editor's search function to know about it, and then keep forgetting it 5 seconds after
doing that).  With C99/C++ style "declare variable on first use", I can tell easily which
assignment is an initialization and which is a modification to previously assigned value, the
latter I'll need to take much more care than the former.

> Having the code go too far to the right is a sign that you should probably break the
function

Of course.  But nothing beats a function that have just one or two levels of indentations: it
doesn't overload myself mentally.  Indentation is a necessary evil, it loads my mental
capability, but if you have a loop body you have to somehow differentiate it from the code
outside the loop, so it is still the best choice.  Using braces also for just variable
declaration leads to quite a few more levels than what I usually want to see in the code,
especially those written by somebody else.

And "break the function" is not always practicible.  Yes it is usually good, and when it is
good it is the best choice.  But at the same time usually it is not good: at times it creates
a whole brunch of functions that has little meaning by itself and has to be called from a
particular context to be useful at all, and the context is in a form of very complex
preconditions involving its arguments, sometimes involving additional structures to hold the
results, the structures, of course, are of little meaning by themselves as well.  A language
feature that provides an alternative when such "golden rule" is not practicible can only be a
good thing.

C89 includes blocks you know...

Posted Jun 10, 2008 22:01 UTC (Tue) by nix (subscriber, #2304) [Link]

Er, that variable declaration included a non-constant. That's not valid 
C89 :)

The only real advantage of intermingling variable declarations like that 
is that their declarations get moved textually closer to their uses. 
That's a significant readability advantage, surely, but C89 isn't C++ (or 
indeed C99): you can't use non-constants in the initializations, so 
there's no efficiency gain from moving declarations around like that.

(GNU C has always allowed arbitrary function calls there, but this is an 
extension to C89.)

C89 includes blocks you know...

Posted Jun 11, 2008 10:07 UTC (Wed) by Yorick (subscriber, #19241) [Link]

No, local (automatic) variables may have non-const initialisers in c89.

C89 includes blocks you know...

Posted Jun 11, 2008 10:23 UTC (Wed) by nix (subscriber, #2304) [Link]

Really? Everything I've found, including my reading of the text of C89, seems to say that
initializers of automatic variables must be constant (and I use a number of compilers on a
daily basis that reject non-constant initializers in C89 mode).

A cite from C89 that supports your interpretation would be nice.

C89 includes blocks you know...

Posted Jun 11, 2008 11:31 UTC (Wed) by ballombe (subscriber, #9523) [Link]

I cannot provide you with one, but info gcc document this extension seems to imply the C89 restriction only apply to aggregate initializers.
5.18 Non-Constant Initializers
==============================

As in standard C++ and ISO C99, the elements of an aggregate
initializer for an automatic variable are not required to be constant
expressions in GNU C.  Here is an example of an initializer with
run-time varying elements:

     foo (float f, float g)
     {
       float beat_freqs[2] = { f-g, f+g };
       /* ... */
     }

C89 includes blocks you know...

Posted Jun 12, 2008 5:17 UTC (Thu) by eru (subscriber, #2753) [Link]

Really? Everything I've found, including my reading of the text of C89, seems to say that initializers of automatic variables must be constant (and I use a number of compilers on a daily basis that reject non-constant initializers in C89 mode).

Well, they are broken compilers. Complain to the vendor.

A cite from C89 that supports your interpretation would be nice.

From my photocopy the original X3.159-1989:
3.5.7 Initialization
[syntax omitted]
Constraints
[...]
All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions.

Since the standard does not specify such constantness constraint for all objects with automatic storage duration, they can be runtime values.

The Rationale section for 3.5.7 makes this even more clear: According to it, the committee even considered allowing automatic aggregate initializers to consist of series of or arbitrary runtime expressions, but did not go that far in the end. The rationale also mentions that a function call that returns a structure is permitted as an initializer for an automatic variable with structure type. I have used some old compilers that had problems with this kind of structure initialization, but they still allowed automatic scalars to be initialized with runtime values. I think even K&R C allowed this.

C89 includes blocks you know...

Posted Jun 12, 2008 10:54 UTC (Thu) by nix (subscriber, #2304) [Link]

OK, broken compilers it is. (It's surprising that a language as apparently simple as C can
still trip one up with unexpected corners like this after so long.)

C89 includes blocks you know...

Posted Jun 12, 2008 16:08 UTC (Thu) by davecb (subscriber, #1574) [Link]

Interestingly, allowing the internal block structure 
can increase the difficulty of doing logic on
the code to the point where building proof tools become
NP-complete (or at least insanely hard).

This is relevant if you're tying to use static analysis
tools, not just if you're trying to prove theoroms (;-))

--dave (who proveth not, but analyzeth a lot) c-b

C89 includes blocks you know...

Posted Jun 19, 2008 17:23 UTC (Thu) by jlokier (guest, #52227) [Link]

Hardly.  C code with blocks and variables declared inside blocks is trivially convertible to a
flat function with all variables at the start, and in trivial time.  Same goes for the control
flow blocks: they are trivially replacable with if (variable) gotos.

So the proof difficulty is identical with/without blocks and local declarations in the
language.


Copyright © 2017, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds