[comp.lang.c] Argument declaration style

jaakola@cc.helsinki.fi (11/06/90)

om>
Followup-To: m>
Xref: hylka comp.lang.c:12516 alt.religion.computers:1470

Organization: University of Helsinki
Lines: 43

In article <_1X6_32@xds13.ferranti.com>, peter@ficc.ferranti.com (Peter da Silva) writes:
> If you do this:
> 
> 	static void auxilary_func(int a)
> 	{
> 		...
> 	}
>
> Everything will work fine. You only need declare it once. Just do it right
> the first time and you won't have to do it again (my father always used to
> tell me that).

Yeah, everything *would* work fine, if we assumed infinite line width!
BUT: - computer screens have finite number of columns
     - my favourite editor has finite line width
     - my printer has finite line width
     - I don't like wrapped lines

I have made an applications generator by simulating object-oriented
methods with plain C (for portability reasons), and I have some
functions with about 10 arguments. And I like descriptive (=long)
names; the arg in the example was "a" for pedagogical reasons...

The most significant advantage of the "old" style is that I can
use the command

	grep \)$ *.c

in UNIX or in MS-DOS with the PICNIX utilities to get output like

myfile.c:int foo(a,b)
mydb.c:BOOL open_db(dbname,audit_file,username,password)
mydb.c:BOOL get_record(key,buffer,bufferlen)
..

The point is: with the old style you can put enough information on a
SINGLE line - the most natural unit of textual information in UNIX-
like environments.
--
Juhani Jaakola, University of Helsinki

karl@ima.isc.com (Karl Heuer) (11/07/90)

In article <3944.27367fb2@cc.helsinki.fi> jaakola@cc.helsinki.fi writes:
>Yeah, everything *would* work fine, if we assumed infinite line width!

It consumes more width than your style, but it also consumes less height.  I
consider that a useful tradeoff, as it makes it more likely that the entire
function will fit on a single screen.  (Also, I very rarely have a function
whose prototype doesn't fit on a single line.)

>The point is: with the old style you can put enough information on a
>SINGLE line - the most natural unit of textual information in UNIX-
>like environments.

This is interesting, because I use the exact same argument in *favor* of the
new style.  If you write
	void foo(x, y)
	  char *x;
	  int y;
	{
and you grep for the declaration, you don't see the types of the arguments.
(And it's even worse if you put the "void" on a separate line!)  With
	void foo(char *x, int y) {
you see all the relevant information at once.  Even with pre-ANSI code I use
	void foo(x, y) char *x; int y; {
for the same reason, but the invention of prototypes made most lines shorter.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint

bzs@world.std.com (Barry Shein) (11/07/90)

You're both wrong, use:

	void
	foo(x,y) int x,y;

Actually, I don't care that much if you put your args on the same line
or next and obviously with long declarations you eventually have to
break up the line (tho main(argc,argv) int argc; char **argv; seems
right, for example.)

But the point is that if you want to find a function's declaration you
should be able to use:

	grep '^foo' *.c

or even better:

	grep '^foo(' *.c

and find *only* the function definiton as that's the only place its
name will begin a line, any use within code will be indented at least
one stop.

I hardly ever want a list of every USAGE of a function, and that's
easy enough to get with this method (grep foo *.c) so it's not an
issue.

It's unfortunate that grep doesn't let you specify what is to be
listed when a hit occurs, the perfect thing would be something like:

	grep ^foo( -L .-1,. *.c

which would list the previous line and the hit (thus giving you
the type and the declaration) or even:

	grep ^foo( -L .-1,/^{/-1 *.c

Right now about the best you could do is use some sort of grep -n and
feed the result of that thru something else which can list particular
lines (sed or similar), but that requires going back thru the file
list for every match if there's more than one.

Seems like grep should have taken ed-like listing specifications as an
option (within reason of course, someone is going to point out how
painful this can be in the worst case, pipes etc, ok, fine, so ed
doesn't work either I suppose...)
-- 
        -Barry Shein

Software Tool & Die    | {xylogics,uunet}!world!bzs | bzs@world.std.com
Purveyors to the Trade | Voice: 617-739-0202        | Login: 617-739-WRLD

tt@tarzan.jyu.fi (Tapani Tarvainen) (11/07/90)

In article <BZS.90Nov6205843@world.std.com> bzs@world.std.com (Barry Shein) writes:

> It's unfortunate that grep doesn't let you specify what is to be
> listed when a hit occurs, the perfect thing would be something like:
> 
> 	   grep ^foo( -L .-1,. *.c
> 
> which would list the previous line and the hit (thus giving you
> the type and the declaration) or even:
> 
> 	   grep ^foo( -L .-1,/^{/-1 *.c

Try this:

#!/bin/sh
# EXDEF
# extract C function definitions & declarations
# usage: exdef function file(s)
# Tapani Tarvainen 7 November 1990
f=$1
shift
sed -e '/^[a-zA-Z_]/!d' -e ':L' -e '/^[^(]*[{;]/d' -e '/(/bR' -e N -e bL \
-e :R -e '/);/!{/{/!{' -e N -e bR -e '}' -e '}' -e "/$f(/!d" $@

Then
	exdef foo *.c

should do what you want, with both old and new style.

I just wrote that and it obviously isn't perfect, e.g., certain
characters in comments within can cause trouble.
Anyway, it prints function definitions from the type up to the { and
declarations up to the semicolon, regardless of how many lines they
occupy.  If you want only definitions or only declarations it's easy
enough to change (except it doesn't distinguish function typedef's
from declarations; add -e '/^typedef/d' before $@ if you don't want
them).
--
Tapani Tarvainen    (tarvaine@jyu.fi, tarvainen@finjyu.bitnet)

kdq@demott.COM (Kevin D. Quitt) (11/07/90)

    We like the ANSI prototypes, and for ease of search/grep, we use the
style:

void foo ( int x, int y )

    This way the only occurance of the function name followed by space parens
is the declaration.
-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

mcdaniel@adi.com (Tim McDaniel) (11/08/90)

Even with prototypes with one argument per line, nobody's holding a
gun to your head to prevent old-style arguments in a comment, if you
want 'grep' to give you such information:

   void foo( /* x, y */
      char *x,   /* a frob string */
      int y      /* plugh value */
   )

By the way: there are grep-like tools that give you a range of lines
around each match.  I don't recall the name, but I think
comp.sources.{unix,misc} has had one.
--
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Work phone: +1 313 973 1300                        Home phone: +1 313 677 4386
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

pmk@craycos.com (Peter Klausler) (11/08/90)

In article <930@demott.COM> kdq@demott.COM (Kevin D. Quitt) writes:
>    We like the ANSI prototypes, and for ease of search/grep, we use the
>style:
>
>void foo ( int x, int y )
>
>    This way the only occurance of the function name followed by space parens
>is the declaration.

I also like ANSI prototypes, but use this style:

void
foo (int x, int y) {
}

so that the function name always appears in column 1.

djones@megatest.UUCP (Dave Jones) (11/08/90)

From article <3944.27367fb2@cc.helsinki.fi>, by jaakola@cc.helsinki.fi:
...

) The most significant advantage of the "old" style is that I can
) use the command
) 
) 	grep \)$ *.c
) 
) in UNIX or in MS-DOS with the PICNIX utilities to get output like
) 
) myfile.c:int foo(a,b)
) mydb.c:BOOL open_db(dbname,audit_file,username,password)
) mydb.c:BOOL get_record(key,buffer,bufferlen)



It is a standard convention to do it like so:

int
foo(a,b)

This way you can find the defining occurance of foo with

% egrep "^foo(" *.c

Sure, I know about "tags", but it is still handy to be able to
grep for the definition in column one.

rjc@uk.ac.ed.cstr (Richard Caley) (11/09/90)

In article <BZS.90Nov6205843@world.std.com> bzs@world.std.com (Barry Shein) writes:

    [how to grep for declarations...]

how about

	% alias defof 'awk "/^\!:1\(/,/\)/ {print}" *.c'
	% defof lpc_synth
	lpc_synth(struct utterance *utterance,
	          struct diphone_set *diphones,     /* must be `open' */
	          struct residual *residual)


(or variations thereof for your indentation style).

extension to print file name, line number and the type of the function
(which is on the line before) are left as an exorcise to the interested
reader. (I don't bother since if want to know where it is I build a
TAGS table and I rarely forget the return type, just the arguments).

--
rjc@uk.ac.ed.cstr		``I saw the wheels of neilism rolling my way
				  and now I live life in the bus lane''
					- Half Man Half Biscuit,
					    `Architecture and Morality'

peter@ficc.ferranti.com (Peter da Silva) (11/09/90)

In article <3944.27367fb2@cc.helsinki.fi>, jaakola@cc.helsinki.fi writes:
> > 	static void auxilary_func(int a)
> > 	{
> > 		...
> > 	}

>      - I don't like wrapped lines

Well, that's a different problem. The standard lets you do what you want,
but you think it's ugly. De gustibus non est disputandum.

> 	grep \)$ *.c

Odd, that gets *me* all my ifs, whiles, and fors as well...

> myfile.c:int foo(a,b)
> mydb.c:BOOL open_db(dbname,audit_file,username,password)
> mydb.c:BOOL get_record(key,buffer,bufferlen)
> ..

Ever hear of ctags?
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com 

karl@ima.isc.com (Karl Heuer) (11/10/90)

In article <1990Nov7.181615.11154@craycos.com> pmk@craycos.com (Peter Klausler) writes:
>I also like ANSI prototypes, but use this style:
>	void
>	foo (int x, int y) {
>	}
>so that the function name always appears in column 1.

Personally, I think the existence of functions like "signal" demonstrates that
this isn't the way God intended functions to be written. :-)

The only advantage I've heard for this is that it makes it easy to find the
function with grep.  I'm willing to endure the hardship of using egrep instead
of grep in exchange for the benefit of having it print out the entire
declaration including type when it does find it.  Besides, my egrep pattern
works on macros too.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint
Followups to alt.religion.computers.

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (11/12/90)

The way I do it is to begin the comment preceding a function
declaration with the sequence /*@F rather than just /*.  Then I use a
perl script (attached) to summarize all functions and their preceding
comments.  (Strip trailing .signature before use.)  It may not work
if you don't use my style, which is:

     /*@F Here's a nice little function that doesn't do very much, but
     on Usenet, who cares? */

     int myfunc(a, b, c);
     int a;
     char *b;
     long c;
     {
       .. function body here

Perl script follows.

#! /where/to/find/perl
# scan file(s) and extract out function headers and comments
# 1990/06/28 R. D.
# Each C function in a file should begin with:
#     /*@F
## Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
## UUCP:  oliveb!cirrusl!dhesi

# When invoked on a C source file (or standard input), this perl
# script prints all functions found.  The output format is:
# a dashed line with the function name; the comments preceding
# the function declaration; and the function declaration.
# The following string, if it begins a comment about a function,
# is not printed:
#    @F

while (<>) {
   if ($inheader) {			# in header;  look for header end 
      if (m"^\s*{")  # match }          #  found end;  print and reset
      {
	 $inheader = 0;
	 if (! $funcname) {
	    $funcname = "UNKNOWN FUNCTION";
	 }
	 printf "\n--- %s ---\n", $funcname;
	 print $descr;
	 $descr = "";
	 $funcname = "";
      } else {						# not found end
	 #s:/\*@F:/*:;
	 # if (!(/\/\*@F\*\// || /\/\*--\*\//))
	 $descr .= $_;					#   collect line
	 if (/^.*\s+(\S+)\s*\([^;]*/ || /^\s*(\S+)\s*\([^;]*/) { 
	    $funcname = $1;   				#   and function name
	    $funcname =~ s/\*//;			#   (delete leading *)
	 }
      }
   } else {				# not in header;  look for one
      if (m"^\s*/\*\@F") {
	 s:/\*@F:/*:;
	 if (! m"^\s*\/\*\*\/\s*$") {
	    $inheader = 1;
	    $descr = $_;
	 }
      }
   }
}
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

salomon@ccu.umanitoba.ca (Dan Salomon) (11/29/90)

In article <1990Nov06.233654.29974@dirtydog.ima.isc.com> karl@ima.isc.com (Karl Heuer) writes:
> ... (Also, I very rarely have a function
> whose prototype doesn't fit on a single line.)
> 
> Even with pre-ANSI code I use
> 	void foo(x, y) char *x; int y; {

This is kind of a wimpy example isn't it?  When working on a large
project like a compiler, or a CAD tool, one tends to get MUCH longer
variable names and type names.  Even two-parameter function headers can
get rather large in such cases.
E.g.

ST_Gen_Class *ST_Lookup_No_Err (char *found_symb; Scope_Level_Ptr Start_Scope);

This is a fictious example, but more resembles my code than does your
example.  With single-letter formal parameter names, the spaces, stars,
and semicolons are quite visible, but with longer parameter and
type names, they tend to get lost.  For long headers like these,
splitting the formal parameters across lines improves readability.
-- 

Dan Salomon -- salomon@ccu.UManitoba.CA
               Dept. of Computer Science / University of Manitoba
	       Winnipeg, Manitoba, Canada  R3T 2N2 / (204) 275-6682

karl@ima.isc.com (Karl Heuer) (12/03/90)

In article <1990Nov28.183850.20592@ccu.umanitoba.ca> salomon@ccu.umanitoba.ca (Dan Salomon) writes:
>In article <1990Nov06.233654.29974@dirtydog.ima.isc.com> karl@ima.isc.com (Karl Heuer) writes:
>>... (Also, I very rarely have a function whose prototype doesn't fit on a
>>single line.)  ... Even with pre-ANSI code I use
>>	void foo(x, y) char *x; int y; {
>
>This is kind of a wimpy example isn't it?  [My code would look more like]
>ST_Gen_Class *ST_Lookup_No_Err (char *found_symb; Scope_Level_Ptr Start_Scope);

I stand by my example.  I find short names easier to read than longer ones, as
long as they're mnemonic.  (In real code the parameters would probably be
named `s' and `n', and if necessary their purpose would be described in a
block comment above the function, which would not be called `foo'.)

In a quick scan of my directory, I find that, of 1491 function definitions in
my style, only 26 of them (1.7%) consume 80 or more columns.

>For long headers like these, splitting the formal parameters across lines
>improves readability.

I strongly disagree.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint