Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #73639 > unrolled thread
| Started by | "Rick C. Hodgin" <rick.c.hodgin@gmail.com> |
|---|---|
| First post | 2015-10-23 10:37 -0700 |
| Last post | 2015-10-23 20:54 -0500 |
| Articles | 13 — 10 participants |
Back to article view | Back to comp.lang.c
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
| From | "Rick C. Hodgin" <rick.c.hodgin@gmail.com> |
|---|---|
| Date | 2015-10-23 10:37 -0700 |
| Subject | C 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]
| From | Melzzzzz <mel@zzzzz.com> |
|---|---|
| Date | 2015-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]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | "Rick C. Hodgin" <rick.c.hodgin@gmail.com> |
|---|---|
| Date | 2015-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]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-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]
| From | "Rick C. Hodgin" <rick.c.hodgin@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Les Cargill <lcargill99@comcast.com> |
|---|---|
| Date | 2015-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]
| From | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Barry Schwarz <schwarzb@dqel.com> |
|---|---|
| Date | 2015-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]
| From | sfisher@panix.com (Stephen Fisher) |
|---|---|
| Date | 2015-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]
| From | Les Cargill <lcargill99@comcast.com> |
|---|---|
| Date | 2015-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