Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #73639 > unrolled thread

C function prototype and body definitions

Started by"Rick C. Hodgin" <rick.c.hodgin@gmail.com>
First post2015-10-23 10:37 -0700
Last post2015-10-23 20:54 -0500
Articles 13 — 10 participants

Back to article view | Back to comp.lang.c


Contents

  C function prototype and body definitions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2015-10-23 10:37 -0700
    Re: C function prototype and body definitions Melzzzzz <mel@zzzzz.com> - 2015-10-23 19:44 +0200
    Re: C function prototype and body definitions Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-23 10:53 -0700
      Re: C function prototype and body definitions Keith Thompson <kst-u@mib.org> - 2015-10-23 12:19 -0700
        Re: C function prototype and body definitions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2015-10-23 12:27 -0700
          Re: C function prototype and body definitions supercat@casperkitty.com - 2015-10-24 10:46 -0700
            Re: C function prototype and body definitions "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2015-10-24 12:17 -0700
      Re: C function prototype and body definitions Les Cargill <lcargill99@comcast.com> - 2015-10-23 20:56 -0500
        Re: C function prototype and body definitions gazelle@shell.xmission.com (Kenny McCormack) - 2015-10-24 09:49 +0000
    Re: C function prototype and body definitions Bartc <bc@freeuk.com> - 2015-10-23 19:16 +0100
    Re: C function prototype and body definitions Barry Schwarz <schwarzb@dqel.com> - 2015-10-23 11:30 -0700
    Re: C function prototype and body definitions sfisher@panix.com (Stephen Fisher) - 2015-10-23 15:58 -0600
    Re: C function prototype and body definitions Les Cargill <lcargill99@comcast.com> - 2015-10-23 20:54 -0500

#73639 — C function prototype and body definitions

From"Rick C. Hodgin" <rick.c.hodgin@gmail.com>
Date2015-10-23 10:37 -0700
SubjectC function prototype and body definitions
Message-ID<ae13b44e-6dd4-4ff6-b62c-c0c8c58fbe50@googlegroups.com>
What is the reason for having both a function prototype and a body
definition, when the body typically replicates the prototype?

||||||||||
|| Why have these:
|| 
||     // myheader.h
||     int my_function(int, int, int);
||         // or this:
||         // int my_function(int a, int b, int c);
|| 
||     // myprogram.c
||     int my_function(int a, int b, int c)
||     {
||         // Code goes here
||     }
||||||

||||||||||
|| Rather than something like this:
|| 
||     // myheader.h
||     int my_function(int a, int b, int c);
|| 
||     // myprogram.c
||     function my_function
||     {
||         // Code goes here
||     }
||||||

?

Best regards,
Rick C. Hodgin

[toc] | [next] | [standalone]


#73640

FromMelzzzzz <mel@zzzzz.com>
Date2015-10-23 19:44 +0200
Message-ID<20151023194414.4c61e009@maxa-pc>
In reply to#73639
On Fri, 23 Oct 2015 10:37:07 -0700 (PDT)
"Rick C. Hodgin" <rick.c.hodgin@gmail.com> wrote:

> What is the reason for having both a function prototype and a body
> definition, when the body typically replicates the prototype?
> 
> ||||||||||
> || Why have these:
> || 
> ||     // myheader.h
> ||     int my_function(int, int, int);
> ||         // or this:
> ||         // int my_function(int a, int b, int c);
> || 
> ||     // myprogram.c
> ||     int my_function(int a, int b, int c)
> ||     {
> ||         // Code goes here
> ||     }
> ||||||
> 
> ||||||||||
> || Rather than something like this:
> || 
> ||     // myheader.h
> ||     int my_function(int a, int b, int c);
> || 
> ||     // myprogram.c
> ||     function my_function
> ||     {
> ||         // Code goes here
> ||     }
> ||||||
> 
> ?
> 

That would definitely put a nail in the coffin of C <-> C++
compatibility ;)

[toc] | [prev] | [next] | [standalone]


#73641

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2015-10-23 10:53 -0700
Message-ID<01da979a-4815-4092-9c2f-e9df44643113@googlegroups.com>
In reply to#73639
On Friday, October 23, 2015 at 6:37:25 PM UTC+1, Rick C. Hodgin wrote:
>
> What is the reason for having both a function prototype and a body
> definition, when the body typically replicates the prototype?
> 
For historical reasons. Prototypes were added at a fairly
late stage in the development of C, whilst argument lists have
been in from the beginning, although they were specified
after the function name rather than in the parentheses. 

However it also means the the programmer has a list of the 
parameters when he's working on the function body, without
having to flip back to the prototype. If you were redesigning
C from scratch, you'd get rid of the prototypes and have some
mechanism for export, rather than keep the prototypes and
get rid of the parameter list at the head of the body.

[toc] | [prev] | [next] | [standalone]


#73647

FromKeith Thompson <kst-u@mib.org>
Date2015-10-23 12:19 -0700
Message-ID<ln4mhhwfyz.fsf@kst-u.example.com>
In reply to#73641
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> On Friday, October 23, 2015 at 6:37:25 PM UTC+1, Rick C. Hodgin wrote:
>> What is the reason for having both a function prototype and a body
>> definition, when the body typically replicates the prototype?
>> 
> For historical reasons. Prototypes were added at a fairly
> late stage in the development of C, whilst argument lists have
> been in from the beginning, although they were specified
> after the function name rather than in the parentheses. 
>
> However it also means the the programmer has a list of the 
> parameters when he's working on the function body, without
> having to flip back to the prototype. If you were redesigning
> C from scratch, you'd get rid of the prototypes and have some
> mechanism for export, rather than keep the prototypes and
> get rid of the parameter list at the head of the body.

Maybe you would.  Personally I think there are considerable advantages
in separating the interface and implementation into separate source
files (e.g., foo.h and foo.c), while having each function definition
repeat the information given by the declaration (with the compiler
checking that it's consistent).  In my experience it isn't difficult to
maintain.

An alternative would be to put everything in a single source file and
perhaps have some extra tool that generates an interface, showing just
the declarations that are "exported" to clients.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#73648

From"Rick C. Hodgin" <rick.c.hodgin@gmail.com>
Date2015-10-23 12:27 -0700
Message-ID<7933df9b-93ab-4023-9a2d-633ca38e861c@googlegroups.com>
In reply to#73647
On Friday, October 23, 2015 at 3:19:19 PM UTC-4, Keith Thompson wrote:
> Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> > On Friday, October 23, 2015 at 6:37:25 PM UTC+1, Rick C. Hodgin wrote:
> >> What is the reason for having both a function prototype and a body
> >> definition, when the body typically replicates the prototype?
> >> 
> > For historical reasons. Prototypes were added at a fairly
> > late stage in the development of C, whilst argument lists have
> > been in from the beginning, although they were specified
> > after the function name rather than in the parentheses. 
> >
> > However it also means the the programmer has a list of the 
> > parameters when he's working on the function body, without
> > having to flip back to the prototype. If you were redesigning
> > C from scratch, you'd get rid of the prototypes and have some
> > mechanism for export, rather than keep the prototypes and
> > get rid of the parameter list at the head of the body.
> 
> Maybe you would.  Personally I think there are considerable advantages
> in separating the interface and implementation into separate source
> files (e.g., foo.h and foo.c), while having each function definition
> repeat the information given by the declaration (with the compiler
> checking that it's consistent).  In my experience it isn't difficult to
> maintain.
> 
> An alternative would be to put everything in a single source file and
> perhaps have some extra tool that generates an interface, showing just
> the declarations that are "exported" to clients.

My CAlive solution is to use an N-pass compiler which does not require
forward declarations or header files, but I do also allow them because
they do make sense in certain projects.

Best regards,
Rick C. Hodgin

[toc] | [prev] | [next] | [standalone]


#73707

Fromsupercat@casperkitty.com
Date2015-10-24 10:46 -0700
Message-ID<cda7cb7c-34eb-464e-bd09-ec5893f7f331@googlegroups.com>
In reply to#73648
On Friday, October 23, 2015 at 2:28:02 PM UTC-5, Rick C. Hodgin wrote:
> My CAlive solution is to use an N-pass compiler which does not require
> forward declarations or header files, but I do also allow them because
> they do make sense in certain projects.

Do common object file formats allow the inclusion of stuff the linker will
ignore?  I would expect they would.  More modern systems allow separately-
compiled files to include information about everything exported thereby,
instead of just a list of names and (possibly section-relative) addresses.

On a related note, how do you see the build process as working?  What I'd
like to see in a build system would be something which kept a directory
for compiler-built intermediate files which could be configured to live
on a non-archived medium, and have the build process say, essentially:

  If source file differs from the last version that was built, run it
  through compiler pass one *without replacing the "last output from
  compiler pass one" files*.  Once that is done, replace the "last
  version that was built" file with the one that was just built.

  If all the files produced by pass one match the previous versions,
  there's no need for pass two.  Otherwise, proceed as previously,
  feeding output to new files, and replacing the "last built pass-one
  files" after pass 2 is complete.

Conventional build systems end up having to rebuild a whole lot of things
when header files get changed, even though in many cases much of the build
time is spent on tasks which will have received substantially the same
input and produced the same output as previously.

In some cases, it may be necessary to have a means of segregating information
which will end up being different on each build but shouldn't force later
build processes to be performed (e.g. it's often useful to have files keep
track internally of when they were produced, and when the files that fed
into them were produced, but it should be possible for a compilation stage
to say, in essence "I have this input which I know produced this output,
and I have this other input which is identical except for build dates; it
should be possible to copy the output but adjust the build date information
[e.g. foo.c changed October 17; foo.pass1 built October 15 conformed October
17; foo.pass2 built October 13 confirmed October 17.]

Have you considered such a thing?  I would think that it lead to huge
reductions in build times.

[toc] | [prev] | [next] | [standalone]


#73723

From"Rick C. Hodgin" <rick.c.hodgin@gmail.com>
Date2015-10-24 12:17 -0700
Message-ID<cf99f1e9-bd4d-44e3-9409-1d9401787546@googlegroups.com>
In reply to#73707
On Saturday, October 24, 2015 at 1:47:22 PM UTC-4, supe...@casperkitty.com wrote:
> On Friday, October 23, 2015 at 2:28:02 PM UTC-5, Rick C. Hodgin wrote:
> > My CAlive solution is to use an N-pass compiler which does not require
> > forward declarations or header files, but I do also allow them because
> > they do make sense in certain projects.
> 
> Do common object file formats allow the inclusion of stuff the linker will
> ignore?  I would expect they would.  More modern systems allow separately-
> compiled files to include information about everything exported thereby,
> instead of just a list of names and (possibly section-relative) addresses.
> 
> On a related note, how do you see the build process as working?  What I'd
> like to see in a build system would be something which kept a directory
> for compiler-built intermediate files which could be configured to live
> on a non-archived medium, and have the build process say, essentially:
> 
>   If source file differs from the last version that was built, run it
>   through compiler pass one *without replacing the "last output from
>   compiler pass one" files*.  Once that is done, replace the "last
>   version that was built" file with the one that was just built.
> 
>   If all the files produced by pass one match the previous versions,
>   there's no need for pass two.  Otherwise, proceed as previously,
>   feeding output to new files, and replacing the "last built pass-one
>   files" after pass 2 is complete.
> 
> Conventional build systems end up having to rebuild a whole lot of things
> when header files get changed, even though in many cases much of the build
> time is spent on tasks which will have received substantially the same
> input and produced the same output as previously.
> 
> In some cases, it may be necessary to have a means of segregating information
> which will end up being different on each build but shouldn't force later
> build processes to be performed (e.g. it's often useful to have files keep
> track internally of when they were produced, and when the files that fed
> into them were produced, but it should be possible for a compilation stage
> to say, in essence "I have this input which I know produced this output,
> and I have this other input which is identical except for build dates; it
> should be possible to copy the output but adjust the build date information
> [e.g. foo.c changed October 17; foo.pass1 built October 15 conformed October
> 17; foo.pass2 built October 13 confirmed October 17.]
> 
> Have you considered such a thing?  I would think that it lead to huge
> reductions in build times.

||||||||||
|| Note:  This relates to CAlive, and not C.  However, the CAlive
||        compiler does provide for significant C90 and C99 support.
||||||

Conceptually, I consider the LiveCode build process to be working on
pieces of a puzzle.  The completed and compiled binary is the puzzle,
and (in a LiveCode environment) the binary can be run without having
all of the puzzle pieces in place.  Whenever it gets to a point where
a needed puzzle piece is missing, then it will suspend execution by
invoking something called an "inquiry."  Inquirys are states where
the runtime suspends to allow program code to be changed to fix the
missing puzzle piece(s), so that the program can continue.

My compiler frame-work is called "Rapid Development Compiler," so it
is a full LiveCode (edit-and-continue or fix-and-continue) framework.

As such, in a LiveCode environment, every puzzle piece has offerings,
needs, and wants.  There are some things each puzzle piece needs to
be included in a binary.  It needs to be targeted for the same system
architecture, it needs to have those things available which it requires
explicitly (libraries, references that it knew about at compile time,
but remain external, and so on).

The linker attempts to put the pieces of the puzzle together, wrapping
everything that fails in inquiry code.

To my knowledge, it's a new way to look at building a binary.  I'm
not trying to build something which runs flawlessly before it is
built.  I am building something that, when everything's coded properly,
will run flawlessly, but up until then, it acknowledges the fact that
it's in a development state, still needing algorithms and code from
the developer to be completed.

It looks at things from the developer's needs throughout the cycle
of development, acknowledging that when everything is coded and
debugged, then the program will be complete, but that really is the
final thing, and not any part of the bulk of the thing which will
exist while the product is being developed.

Best regards,
Rick C. Hodgin

[toc] | [prev] | [next] | [standalone]


#73672

FromLes Cargill <lcargill99@comcast.com>
Date2015-10-23 20:56 -0500
Message-ID<n0eo59$epe$2@dont-email.me>
In reply to#73641
Malcolm McLean wrote:
> On Friday, October 23, 2015 at 6:37:25 PM UTC+1, Rick C. Hodgin wrote:
>>
>> What is the reason for having both a function prototype and a body
>> definition, when the body typically replicates the prototype?
>>
> For historical reasons. Prototypes were added at a fairly
> late stage in the development of C, whilst argument lists have
> been in from the beginning, although they were specified
> after the function name rather than in the parentheses.
>
> However it also means the the programmer has a list of the
> parameters when he's working on the function body, without
> having to flip back to the prototype. If you were redesigning
> C from scratch, you'd get rid of the prototypes and have some
> mechanism for export, rather than keep the prototypes and
> get rid of the parameter list at the head of the body.
>


I might actually not do that.

"import someFunction" is lossy
with respect to
"extern int someFunction(int a,int b);"

-- 
Les Cargill

[toc] | [prev] | [next] | [standalone]


#73677

Fromgazelle@shell.xmission.com (Kenny McCormack)
Date2015-10-24 09:49 +0000
Message-ID<n0fk86$umi$3@news.xmission.com>
In reply to#73672
In article <n0eo59$epe$2@dont-email.me>,
Les Cargill  <lcargill99@comcast.com> wrote:
...
>I might actually not do that.
>
>"import someFunction" is lossy
>with respect to
>"extern int someFunction(int a,int b);"

Rick is proposing that if you have the typical usage, like this:

$ cat someFunction.h
extern int someFunction(int a,int b);
$ cat someFunction.c
#include "someFunction.h"

int someFunction(int a, int b) {
    /* Implementation of someFunction */
    }

$

Then at the point of the function declaration, the compiler already knows
the function's signature, so why repeat it?

What exactly this has to do with "import"ing anything, I can't quite see.

-- 
The book "1984" used to be a cautionary tale;
Now it is a "how-to" manual.

[toc] | [prev] | [next] | [standalone]


#73643

FromBartc <bc@freeuk.com>
Date2015-10-23 19:16 +0100
Message-ID<n0dtd7$atc$1@dont-email.me>
In reply to#73639
On 23/10/2015 18:37, Rick C. Hodgin wrote:
> What is the reason for having both a function prototype and a body
> definition, when the body typically replicates the prototype?
>
> ||||||||||
> || Why have these:
> ||
> ||     // myheader.h
> ||     int my_function(int, int, int);
> ||         // or this:
> ||         // int my_function(int a, int b, int c);
> ||
> ||     // myprogram.c
> ||     int my_function(int a, int b, int c)
> ||     {
> ||         // Code goes here
> ||     }
> ||||||

Because that's how C has worked and how it works now.

Although I'm not sure why they can't fix it so that you don't have to 
replicate everything. Probably no one can agree exactly how...

>
> ||||||||||
> || Rather than something like this:
> ||
> ||     // myheader.h
> ||     int my_function(int a, int b, int c);
> ||
> ||     // myprogram.c
> ||     function my_function
> ||     {
> ||         // Code goes here
> ||     }
> ||||||


That's not very appealing either! Half of the function definition exists 
in a different location. (Although I have had something similar to that 
in one of my languages; it was a nightmare.)

For local (static) functions, it is easy, you can write (perhaps with a 
'static' prefix):

|     // myprogram.c
|     int my_function(int a, int b, int c)
|     {
|         // Code goes here
|     }

The compiler ought to take of this. Actually it does so now - *if* 
functions are always defined before use. But you don't want to worry 
about what order functions written or pasted or how they might be moved 
around.

For exported, global or shared functions, ideally you don't want to 
write much more. But how it ought then to work is more controversial.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#73646

FromBarry Schwarz <schwarzb@dqel.com>
Date2015-10-23 11:30 -0700
Message-ID<o1uk2btmdpjk8qg7o116s29t6f7bp92ri2@4ax.com>
In reply to#73639
On Fri, 23 Oct 2015 10:37:07 -0700 (PDT), "Rick C. Hodgin"
<rick.c.hodgin@gmail.com> wrote:

>What is the reason for having both a function prototype and a body
>definition, when the body typically replicates the prototype?
>
>||||||||||
>|| Why have these:
>|| 
>||     // myheader.h
>||     int my_function(int, int, int);
>||         // or this:
>||         // int my_function(int a, int b, int c);
>|| 
>||     // myprogram.c
>||     int my_function(int a, int b, int c)
>||     {
>||         // Code goes here
>||     }
>||||||
>
>||||||||||
>|| Rather than something like this:
>|| 
>||     // myheader.h
>||     int my_function(int a, int b, int c);
>|| 
>||     // myprogram.c
>||     function my_function
>||     {
>||         // Code goes here
>||     }
>||||||

It is a language requirement that a function be declared before it is
called.  The compiler needs to know how the function should be called
and what, if any, conversions should be performed on the arguments.
Furthermore, the linker requires that there be exactly one function to
resolve a reference to an external function.

If the only declaration for the function is also its definition, then
there are at least two cases where the requirements cannot be met
without a prototype:

1 - Consider the case of two functions, either of which can call the
other.
     my_func1(....){
          if (some_condition){my_func2(....)}
         ....}
     my_func2(.....){
          if (some_other_condition)(my_func1(....)}
          ....}

The obvious solution is to put a prototype for each function in a
header and the function definitions in a C file which includes the
header.

2 - Consider the case where you have multiple C files which contain
calls to my_func.  If you put the function definition in one of those
files, the other files will not have a visible declaration at the
point where they call the function.  If you put the function
definition in a file by itself and include that file in each of the
others, the linker will complain about multiple functions with the
same name.  If you put the function in all the files, the linker will
also complain about multiple functions with the same name.  (Even
worse, it is a maintenance nightmare since any change to the function
must be repeated in all the files.)

The obvious solution is to put the prototype in a header, the function
in a stand alone file, and include the header in each of your C files
from which the function is called.  There is now a declaration visible
in each of the C files to make the compiler happy and only one copy of
the function to make the linker happy.

-- 
Remove del for email

[toc] | [prev] | [next] | [standalone]


#73661

Fromsfisher@panix.com (Stephen Fisher)
Date2015-10-23 15:58 -0600
Message-ID<n0eaha$ech$1@panix3.panix.com>
In reply to#73639
In article <ae13b44e-6dd4-4ff6-b62c-c0c8c58fbe50@googlegroups.com>,
Rick C. Hodgin <rick.c.hodgin@gmail.com> wrote:

>What is the reason for having both a function prototype and a body
>definition, when the body typically replicates the prototype?

A practical reason for me would be so that I remember the variable types and
names while writing the function.  I usually copy the prototype into the
header afterwards.

[toc] | [prev] | [next] | [standalone]


#73671

FromLes Cargill <lcargill99@comcast.com>
Date2015-10-23 20:54 -0500
Message-ID<n0eo0o$epe$1@dont-email.me>
In reply to#73639
Rick C. Hodgin wrote:
> What is the reason for having both a function prototype and a body
> definition, when the body typically replicates the prototype?
>
> ||||||||||
> || Why have these:
> ||
> ||     // myheader.h
> ||     int my_function(int, int, int);
> ||         // or this:
> ||         // int my_function(int a, int b, int c);
> ||
> ||     // myprogram.c
> ||     int my_function(int a, int b, int c)
> ||     {
> ||         // Code goes here
> ||     }
> ||||||
>
> ||||||||||
> || Rather than something like this:
> ||
> ||     // myheader.h
> ||     int my_function(int a, int b, int c);
> ||
> ||     // myprogram.c
> ||     function my_function
> ||     {
> ||         // Code goes here
> ||     }
> ||||||
>
> ?
>
> Best regards,
> Rick C. Hodgin
>


Because the prototype isn't just a prototype, it's a contract.
The declaration has to match the protoype or it
can't work.

It's also quite convenient to have the arguments
spelled out in the function declaration.



-- 
Les Cargill

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web