ark@alice.UUCP (03/20/88)
Here is one sensible way to deal with prototypes:
Suppose you are writing a function to be used by others.
Let's call it foo(). Declare it in foo.h:
extern double foo (int, char *, long);
When you write foo.c, be sure to include foo.h:
#include "foo.h"
double foo (int n, char *p, long size)
{
/* stuff */
}
Indeed, you have stated foo's signature twice.
However, the compiler should reject an attempt to
compile foo.c if the two instances do not match.
Now a user who includes foo.h will automatically
get the right declaration.
henry@utzoo.uucp (Henry Spencer) (03/27/88)
> ... Declare it in foo.h... When you write foo.c, be sure to include foo.h... > Indeed, you have stated foo's signature twice. > However, the compiler should reject an attempt to > compile foo.c if the two instances do not match. There is still one headache with this, a more general flaw of foo.h schemes: significant information is still present in two different files, and keeping them in step can be a headache (even if failures are detected at compile time). I've been experimenting with a simple solution to this that works moderately well. It's a variant on the idea of automatically generating function prototypes from the function code (which isn't simple to do and doesn't address the other things that one might want to put in a header). The idea is to imbed the foo.h information in foo.c, marked so that it can be extracted automatically. This still means you have to *write* it twice, but the two instances can be *together*, which makes synchronized changes much easier. The particular marking convention I use is based on an extension of another notation I already use: beginning all lines of a multi-line comment with " *" except for a line in the comment at the head of each function describing the function, which begins with " -". (This isn't original, although I no longer remember exactly who gave me the idea.) So I use "=" to mark a line meant for foo.h. This may be obscure without an example, so here's how I might start an implementation of strcpy() (ignore the leading tabs): /* - strcpy - copy string from b to a = extern char *strcpy(char *a, char *b); * * Using algorithm XYZ to run fast on machine ABC. */ char * strcpy(a, b) char *a; char *b; { /* ... */ A simple "egrep '^ -'" will give me the "definition" lines for all the functions, and a slightly more complex bit of code (see below) will build a suitable header file. Note that I can put *anything* into the header file this way, not just function prototypes. Note also that I can write ANSI prototypes even for a non-ANSI compiler; my header-file builder takes an "old compiler" option that comments out the parameter list. (It also turns C++-style // comments in the = lines into C comments, because otherwise it's hard to get C comments onto such lines.) Without further ado, here's what I call "mkh"; I recommend it. (Oh, ignore the -p option, it's still experimental.) ----------- X# mkh - pull headers out of C source XPATH=/bin:/usr/bin ; export PATH X Xpeel=' /^ ==*[ ]/ /\/\//s;//\(.*\);/*\1 */; X s/^ ==*[ ]//' X Xegrep='^ =[ ]' X Xfiles= Xfor a Xdo X case "$a" X in X -o) # old (pre-function-prototype) compiler X peel='/^ ==*[ ][^#]/{ /^\([^\/]*[a-zA-Z0-9_)]\)(\(.*\))/s;;\1(/*\2*/); X } X '"$peel" X echo '#ifdef __STDC__' X echo '#error "header file prepared with mkh -o"' X echo '#endif' X ;; X X -p) # include private declarations X egrep='^ ==*[ ]' X ;; X X *) X files="$files $a" X ;; X esac Xdone X Xfor f in $files Xdo X egrep "$egrep" $f | sed "$peel" Xdone ----------- -- "Noalias must go. This is | Henry Spencer @ U of Toronto Zoology non-negotiable." --DMR | {allegra,ihnp4,decvax,utai}!utzoo!henry
rang@cpsin3.cps.msu.edu (Anton Rang) (04/29/89)
Is it possible to declare a prototype with an "optional" final argument? I'm trying to do a prototype for BSD's "open", which takes either 2 or 3 arguments. At the moment, I have: extern int open(char *, int, ...); Is there any way to limit this to only take 2 or 3 arguments (as opposed to 2 or more)? +---------------------------+------------------------+-------------------+ | Anton Rang (grad student) | "VMS Forever!" | VOTE on | | Michigan State University | rang@cpswh.cps.msu.edu | rec.music.newage! | +---------------------------+------------------------+-------------------+ | Send votes for/against rec.music.newage to "rang@cpswh.cps.msu.edu". | +---------------------------+------------------------+-------------------+
karl@haddock.ima.isc.com (Karl Heuer) (04/30/89)
In article <2775@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes: >I'm trying to do a prototype for BSD's "open" BSD? I thought AT&T was to blame for that mistake. > extern int open(char *, int, ...); >Is there any way to limit this to only take 2 or 3 arguments (as >opposed to 2 or more)? No. The prototype you gave is the best possible under the circumstances. (Except that the first arg should be declared with "const".) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
rdw2030@venus.tamu.edu (06/29/90)
With all this talk about prototypes lately, I must admit... though I've been programming in C for years, I've never understood why they exist! Programs run without them! My question... why prototypes? I know they are part of the ANSI standard, but what is their purpose!? Mark C. Lowe - KB5III
henry@zoo.toronto.edu (Henry Spencer) (07/08/90)
In article <55550@lanl.gov> rdw2030@venus.tamu.edu writes: >... I've never understood why they exist! Programs run without them! >My question... why prototypes? ... They make it possible for the compiler to do type checking that formerly had to be done by the programmer or lint (both error-prone, the former because of human frailty and the latter because too many people either don't have it or won't use it). They also give the compiler more information about how functions are called, which permits optimized calling sequences of various kinds. Notably, it is no longer necessary for the compiler to assume that any function might be a varargs function, so non-varargs calls need not be constrained by the tricky requirements of varargs. Also of note for the numerical community is the ability to pass floats as floats and not have them widened to double, which can be costly. -- "Either NFS must be scrapped or NFS | Henry Spencer at U of Toronto Zoology must be changed." -John K. Ousterhout | henry@zoo.toronto.edu utzoo!henry
david@csource.oz.au (david nugent) (07/09/90)
In <55550@lanl.gov> rdw2030@venus.tamu.edu writes: >With all this talk about prototypes lately, I must admit... though I've been >programming in C for years, I've never understood why they exist! Programs >run without them! Sure. >My question... why prototypes? I know they are part of the ANSI standard, but >what is their purpose!? Simple - type checking, and the benefit of implied type casting. The latter is particularly good in a memory segment (ugh!) environment, and takes care of near/far pointer conversion. By using prototypes, you lessen the need to ever need to use LINT; for basic maintenance, anyway. They've saved me many hours of frustrating bug-busting by allowing the compiler to check types passed as parameters. Converting from a situation where you use none to using prototypes should a) be annoying as hell, and b) be rewarding in the long run. david -- _______________________________________________________________________________ Unique Computing Pty Ltd Melbourne Australia - Communications Specialists david@csource.oz.au 3:632/348@fidonet 28:4100/1@signet
stever@Octopus.COM (Steve Resnick ) (07/10/90)
In article <559@csource.oz.au> david@csource.oz.au (david nugent) writes: >In <55550@lanl.gov> rdw2030@venus.tamu.edu writes: > >>With all this talk about prototypes lately, I must admit... though I've been >>programming in C for years, I've never understood why they exist! Programs >>run without them! > >>what is their purpose!? > [I know this is referenced wrong but I missed the original] There are a few "ansi" compilers around which are "broken" without prototypes. In Turbo C, for instance, calling malloc without the prototype doesn't work in large memory model (eg returns a 32bit pointer) becuase it (correctly) assumes that the function returns an int. (I found this out by getting my pointer value returned with the upper 16 bits set to zero and pointing into the interrupt vector table on my PC - real nice "feature" (-8). Turbo C has also made assumptions about function arguments being ints as well. I have also encountered this on Microsoft C. The bottom line is that when you provide your compiler with a prototype, the compiler shouldn't make any assumptions about what's being passed or returned and you get much better error checking. (Even though it's a pain in the arse to get used to doing at first!) There are a few compilers which will generate the prototypes for you, too! (Microsoft for instance) Adding my $.02 to the pot, now deal the cards! :) Steve -- -------------------------------------------------------------------------------- Steve Resnick -<stever@octopus.COM apple!octopus!stever sun!vsi1!octopus!stever> 408/241-1533 Process Scientific, Inc. "0x2B|~0x2B THAT is the question!"
gordon@osiris.cso.uiuc.edu (John Gordon) (07/11/90)
The purpose of a prototype is to explicitly declare what type the function returns (if any) and what types the function takes as args (if any). This makes it easier to detect errors involving incorrect returns and arg passing to and from functions. --- John Gordon Internet: gordon@osiris.cso.uiuc.edu #include <disclaimer.h> gordon@cerl.cecer.army.mil #include <clever_saying.h> GEnie: j.gordon14
peter@msinc.msi.com (Peter Blemel) (08/24/90)
It has been noted that the linker *should* resolve symbols to local code before resolving them from a library. Two problems arise from this assumption in my personal experience: 1) I decided to rewrite a function, but I changed the order of the arguments: If the system I am porting to has ansi prototypes the compiler will bomb on the code declaring that my arguments are incorrect. I had used index as a global int within a file (properly declaring it, and referencing it), but when I tried to port the code to a machine with prototypes, the compiler choked on my use of index because of the prototype definition, effectively making index a reserved word. Should functions in the standard c library be forced as reserved words? 2) In an even worse oversight, Apollo has implimented shared libraries including the lex library libl.a. My application needed a very large yytext[] array, so I declared it myself and the Sun/VAX/IBM linkers correctly used my array because I do not include -ll in the arguments to ld. The Apollo linker automagically loads all of the shared libraries, so that even though I do *not* specify -ll at link time, it is still loaded and a multiply defined symbol yytext is produced. My code (under these conditions) can not be ported without a rewrite becuase I need the expanded yytext buffer. Peter Blemel ---------------- unmvax.cs.unm.edu!bbx!yenta!msinc!peter