Syntax for union parameter

R

Rick C. Hodgin

Note: I tried to post this a few times. There were errors. I apologize
if it is double- or multi-posted. I do not see it presently, which
is why I am now re-posting it.

Best regards,
Rick C. Hodgin

-----
I can think of no good reason to use non-prototype declarations
or definitions. (Saving a few characters is not IMHO a good reason.)

It doubles your workload. It introduces places where there can be
errors / discrepancies. I ran into two last night. I had something
defined as ** in the prototype, but as * in the function. It had
been some time since I wrote the code so I had to figure out which was
correct. It turned out * was correct, which was the function
definition and the prototype in another file simply was not updated.
And since I had not used that function yet, it was a silent error
that cropped through.

Had I defined it one place it would be right or wrong in one place.
As it is with prototypes one needs a truth table:

Prototype | Function
--------------------
Right | Right
Right | Wrong
Wrong | Right
Wrong | Wrong

If I have only the function definition, which serves also as the
prototype it becomes much easier:

Function
--------
Right
Wrong

Easy to track down. Easy to identify the cause. Errors are a constant,
not a variable. You know things rather than are guessing at things.
It helps the digestion, rather than causing it to become irritated.
And so on.

It's a no brainer, IMHO.

Best regards,
Rick C. Hodgin
 
I

Ian Collins

Rick said:
Note: I tried to post this a few times. There were errors. I apologize
if it is double- or multi-posted. I do not see it presently, which
is why I am now re-posting it.

Best regards,
Rick C. Hodgin

-----


It doubles your workload. It introduces places where there can be
errors / discrepancies. I ran into two last night. I had something
defined as ** in the prototype, but as * in the function.

Then it wouldn't have compiled with a C compiler.
 
R

Rick C. Hodgin

Then it wouldn't have compiled with a C compiler.

It did compile because I had not referenced the function previously. I
had written it, and I had it available. However, until that function
was used, the fact that it had a discrepancy between the forward prototype
definition and the actual function declaration was of no consequence. No
C compiler would catch that (at least not automatically, because having
those discrepancies are not errors).

However, when I tried to use the function as per its forward prototype
declaration, it now generated a link-time error because it could not
find the function with the **.

Had I only used one declaration, the function declaration, as both the
prototype and function declaration, then it would never have been an
error.

Best regards,
Rick C. Hodgin
 
J

James Kuyper

Let's call these forward declarations rather than prototypes.

In C, as currently defined, they are both forward declarations and
prototyped declarations. Forward declarations can be non-prototyped or
prototyped. It might be better to choose either new terms not already
defined with a different meaning, or current terms with exactly their
current meaning.
 
S

Seebs

Did you expect any better from a religious zealot?

I know a large number of religious zealots who are more willing to
consider the possibility that they are wrong. So yes.

-s
 
K

Keith Thompson

BartC said:
You've confused me know with this post.

Whatever the official meaning of prototype, what I (and I think Rick) take
to be function prototypes are a separate set of declarations which declare
the names, numbers and types of parameters, and return types of functions
defined elsewhere. In the case of local functions, later on in that file.

I can't help how somebody else uses the word "prototype", other than to
point out the correct definition of the word. The term is defined in
C11 6.2.1:

A *function prototype* is a declaration of a function that declares
the types of its parameters.

Prototypes are a subset of function declarations.

A function definition provides a function declaration.

The distinction I'm making is between function declarations that are
prototypes and function declarations that are not prototypes. I'm
suggesting that there is (almost) never any good reason to use the
latter.
Take the C code I posted elsewhere in the thread, which I said was
code-generated. Take out the prototype declarations, and it will give a
compile error, especially if you rearrange the function definitions. Those
separate prototypes are necessary (at least, in the compiler I use), unless
you arrange the definitions in a certain order.

You can sometimes avoid *separate* prototypes by ordering your function
definitions, so that each function precedes any function that calls it.
That's often more trouble than it's worth, and it doesn't work in the
presence of mutually recursive calls.
The problem is this means declaring many things twice, and that leads to
maintenance issues.

That can be avoided by putting prototypes in header files that can be
shared by multiple translation units. There's still some duplication,
but if "foo.c" defines a function foo(), "foo.h" declares the same
function, and "foo.c" has a #include directive for "foo.h", then any
inconsistency will be caught by the compiler.
Rick is right in that the need for prototypes can easily be eliminated (in
the input source code), which is exactly what I've done in the C
preprocessors, and translators to C, that I've worked on. Of course the
generated C (and associated headers for things that are exported) needs to
have those inserted, but it's no longer a programmer responsibility.

If you have function definitions (as any C program must), then those
function definitions provide function declarations. I'm saying, among
other things, that there is no good reason for those declarations not to
be prototypes.
 
J

James Kuyper

On 01/29/2014 02:28 PM, Rick C. Hodgin wrote:
....
It doubles your workload.

I think you're confusing prototypes with separate declarations. Having a
separate declaration from the one that forms part of your function
definition does double your workload, if it's a prototyped declaration.

Writing a prototype declaration for a function rather than a
non-prototyped declaration for that same function requires very little,
if any, extra work, if it's the declaration that appears at the top of
the definition; the main part of the work is the list of parameter names
and types, and those are present whether or not you use a prototype;
it's just a slight difference is the syntax surrounding and separating
that list.

On the other hand, using a prototyped declaration rather than a
non-prototyped declaration involves a lot more than twice as much work
if it's a declaration that's separate from the definition, since the
non-prototyped declaration doesn't need to have the argument type list.
... It introduces places where there can be
errors / discrepancies. I ran into two last night. I had something
defined as ** in the prototype, but as * in the function. It had
been some time since I wrote the code so I had to figure out which was
correct. It turned out * was correct, which was the function
definition and the prototype in another file simply was not updated.
And since I had not used that function yet, it was a silent error
that cropped through.

You should have #included the separate declaration into the same
translation unit with the definition. If you had, the error would not
have been silent.
If I have only the function definition, which serves also as the
prototype it becomes much easier:

Function
--------
Right
Wrong

Easy to track down. Easy to identify the cause. Errors are a constant,
not a variable. You know things rather than are guessing at things.
It helps the digestion, rather than causing it to become irritated.
And so on.

It's a no brainer, IMHO.

I'm suspicious of any decision described as a "no brainer"; far too
often, I've found that it's a decision that would not have been chosen
by those who do use their brains.

In this case, using the function definition as the function prototype
means that you cannot use the function prototype to validate a call to
the function until that function has been defined. You could start with
an empty definition, and more fully define it later. But that's
essentially what C's separate declarations are: a function definition
without a function body.
 
K

Keith Thompson

Rick C. Hodgin said:
I'll gladly resign from this conversation because my views are not related
to C, but rather what C should've been (in my opinion), based on the 2000+
direction of hardware abilities.

Excellent.
 
B

Ben Bacarisse

Rick C. Hodgin said:
There are cases where it is more advantageous to have prototype declarations,
such as these examples you state. If I am compiling something that will be
linked in later, then it may not be desirable to parse the entire source file
to obtain the function declarations as prototypes themselves. As such, the
need for those prototype declarations are desirable.

Still, there should be no reason any human being has to write them in any
case. The compiler can parse the function declarations and create the
prototype file as a mechanical operation of the compiler, rather than of
the developer. Compilers won't make mistakes once they're coded and
debugged. People will.

You may not have the source file and/or it may not be written in
whatever this language is. Unless you are designing for a walled
garden with very high walls, you'll want to be able to describe an
external function in such a way that the calling code can do what is
needed.
And for systems which are integrated using the tools available today as
they relate to hardware, there is no longer any reason whatsoever for
any human being to maintain any aspect of mechanical conveyance of
something internal to an application. The computer's entire existence
is to help man increase productivity. I am not well served by doing
lots of mechanical typing when the computer itself can, through multiple
threads on multiple cores with gigabytes of memory, re-parse the entire
source code file of the Linux kernel, for example, in near real-time.

So, for example, why not implement type inference? Much less typing and no
possibility of error[1].
The fact is C looks backwards, to a time when machines were limited.

Yes, which is why I was surprised that you wanted to designed a
language "based on C", and that you seem resistant to looking into
modern programming language design.
There are MANY facets of C that should be revisited, and the cojoined
nature of the advanced edit-and-continue C compiler and IDE should be
acknowledged as the future.

Must we sign a pledge? Do we line up and salute the IDE? People like
to use familiar tools that work well for them. The liberal approach is
to provide tools that inter-work, both with each other and with existing
tools. If you offer just a fascist slab of an IDE, you won't get
anywhere with your target users (which seems to be free software
aficionados). Large companies and governments have the clout to impose
the One True IDE, but you don't.
My opinion. C needs to change.

It does, and will continue to do so, but you probably won't be able to
have any influence on how.
I will actually introduce a C compiler
at some point into my RDC toolchain.

Old C or C of the 1999 standard or then 2011 one?

<snip>
[1] Let's ignore Curry-Howard for the moment.
 
E

Eric Sosman

[...]
Let's call these forward declarations rather than prototypes.

In C as it is now, they would still be needed, for external and some local
functions (the legacy of C allows you to get away without some of them, but
that is too lax in my view).

s/is/was/, for the last fifteen years.
 
B

Ben Bacarisse

BartC said:
Let's call these forward declarations rather than prototypes.

Why forward? In the brave new world, the compiler is multi-pass. They
can surely all be at the end of a source file just as well as anywhere
else.
In C as it is now, they would still be needed, for external and some local
functions (the legacy of C allows you to get away without some of them, but
that is too lax in my view).

However, in a tweaked version of C, or this new 'RDC', they can be
eliminated. In the C syntax wrappers I've worked on, they largely have
been.

This is getting out of hand. We have no idea at all about what RDC is,
so how can we speculate? If it has run-time types there's no need for
any compiler-time type checking. We are in the dark.

The best we can do is consider something "based on C" that is an
incremental change. If it has compile-time type-checking of function
calls, then something is needed for those cases when the source of the
function being called is not available, or when it is in some language
that RDC can't type-check. That seems to mean that "forward
declarations" can't be eliminated.

<snip>
 
K

Keith Thompson

Rick C. Hodgin said:
It did compile because I had not referenced the function previously. I
had written it, and I had it available. However, until that function
was used, the fact that it had a discrepancy between the forward prototype
definition and the actual function declaration was of no consequence. No
C compiler would catch that (at least not automatically, because having
those discrepancies are not errors).

However, when I tried to use the function as per its forward prototype
declaration, it now generated a link-time error because it could not
find the function with the **.

Had I only used one declaration, the function declaration, as both the
prototype and function declaration, then it would never have been an
error.

The conventional way to deal with this is for all functions intended
to be used by multiple translation units to be declared in header
files. (Functions used only in a single translation unit needn't
be declared in any header, and should be defined as "static".)

Any ".c" file that either defines or refers to a function has a
#include directive for the header that declares it. That means
writing the declaration twice, but any discrepancy will be caught
by the compiler. (Writing the duplicate declaration is a simple
matter of copy-and-paste.)

Following this convention probably would have prevented the problem
you're talking about.

If you have a function call with no visible declaration, and the
compiler accepts it, it's probably because the compiler is operating
under pre-C99 rules -- but even if you're using a pre-C99 compiler,
providing visible declarations for all functions is still good
practice.

One can certainly imagine some non-C language in which declarations
need not precede reference to functions, as long as the declaration
appears *somewhere*. And you may be able to get away with pretending
that you're programming in such a language if your pre-C99 compiler
doesn't enforce the C99 rules. But it will not detect argument
mismatch errors.

C certainly allows you to be sloppy. That's why discipline is so
important.

As for what you can do in some language other than C, perhaps of
your own invention, I frankly do not care.
 
B

Ben Bacarisse

Ian Collins said:
Then it wouldn't have compiled with a C compiler.

It was in another file. The problem was not using a shared include
file, as best as I can make out. Using one is standard in C, but it's
easy to forget that the language does not enforce good practise in this
regard. Using a header file, you get an error immediately you change
something. You do have two copies, but they never get out of sync for
longer than it takes to type "make".
 
R

Rick C. Hodgin

You may not have the source file and/or it may not be written in
whatever this language is. Unless you are designing for a walled
garden with very high walls, you'll want to be able to describe an
external function in such a way that the calling code can do what is
needed.

I am designing systems that interface with C systems, or with something
to which I have an interface. In those cases where I am writing to
something which is external, I have no problem manually creating the
file because that's just the cost of doing business. For everything
that is inside the C ecosystem, I should never have to do that.
And for systems which are integrated using the tools available today as
they relate to hardware, there is no longer any reason whatsoever for
any human being to maintain any aspect of mechanical conveyance of
something internal to an application. The computer's entire existence
is to help man increase productivity. I am not well served by doing
lots of mechanical typing when the computer itself can, through multiple
threads on multiple cores with gigabytes of memory, re-parse the entire
source code file of the Linux kernel, for example, in near real-time.

So, for example, why not implement type inference? Much less typing
and no possibility of error[1].

I mentioned something like that in a previous thread. I see no reason why
it can't do that, and allow the linker to fixup issues, and report ultimat
errors. However, there are some considerations for things like
int k = foo(4) which gets translated to an int foo(float) function. Since
4 was specified as an integer, was the intended function the float version?
Or was the intent to use int k = foot(4) which was defined as int foot(int)?

There are reasons to use definitions. They make sense. But, there are no
reasons to use forward prototype definitions in C when you have access to
the source files, except for those cases where you are doing compilation
to something external which needs the references to create its object file.
For everything else, the compiler should be able to handle it.
Yes, which is why I was surprised that you wanted to designed a
language "based on C", and that you seem resistant to looking into
modern programming language design.

I like C because it's low level. However, there are aspects of C which
are not forward-looking. My desires with RDC are to mate those two
together (forward-looking, and low-level).
Must we sign a pledge? Do we line up and salute the IDE?
LOL!

People like
to use familiar tools that work well for them. The liberal approach is
to provide tools that inter-work, both with each other and with existing
tools. If you offer just a fascist slab of an IDE, you won't get
anywhere with your target users (which seems to be free software
aficionados). Large companies and governments have the clout to impose
the One True IDE, but you don't.

That's why I'm writing something new with RDC and not writing another
C compiler. I'm beginning with the premise of the integrated IDE which
knows the system you're working with, and is part of the integrated
system ecosystem.
It does, and will continue to do so, but you probably won't be
able to3have any influence on how.

Agreed. :)
Old C or C of the 1999 standard or then 2011 one?

Yes. I would support standards in my C compiler add-on for RDC.

Best regards,
Rick C. Hodgin
 
R

Rick C. Hodgin

The conventional way to deal with this is for all functions intended
to be used by multiple translation units to be declared in header
files. (Functions used only in a single translation unit needn't
be declared in any header, and should be defined as "static".)

That is what I did. However, I had not yet used the file. So, as far
as the compiler knew they were two separate functions, but since neither
was referenced it just removed them from the output, or compiled them as
they were and since nothing called them they were ignored.

When I used the function in my code my usage corresponded to the forward
prototype definition. However, the linker could not find that function
because it did not exist. I had to reconcile the issue between my
forward declaration and my function definition. And at that point it
became a research project to figure out which one was correct. It
didn't take long, but it took a minute. The function definition was
correct and I changed the prototype and it worked. That occurred on
four functions actually IIRC, and they were all ** and * variances as
I had changed the code at one point but didn't change the forward
prototype.
Any ".c" file that either defines or refers to a function has a
#include directive for the header that declares it. That means
writing the declaration twice, but any discrepancy will be caught
by the compiler.

Only if the function is used.
(Writing the duplicate declaration is a simple matter of
copy-and-paste.)

So now I'm spending time copy-and-pasting something an intelligent
compiler would otherwise be capable of knowing for itself? "Manual
effort exerted by every use to maintain an outdated standard" is
what it sounds like to me.
Following this convention probably would have prevented the problem
you're talking about.

Not in this case. I did follow that convention, but the compiler had
no way of reconciling the two because the function was never used.
If you have a function call with no visible declaration, and the
compiler accepts it, it's probably because the compiler is operating
under pre-C99 rules -- but even if you're using a pre-C99 compiler,
providing visible declarations for all functions is still good
practice.

You have misunderstood. I do believe by the time you read this line
that you will have understood my particular case, but I will explain
it plainly just in case.

Somewhere I forward declared:

int foo(char** x);

And in my code I wrote the function:

int foo(char* x) { // Code goes here }

I did not call foo() anywhere in my code. As such, the compiler saw
the forward prototype and the function body and logically created two
separate functions internally. But, since none of them were called
it simply discarded them. An error in code, but no way the compiler
could catch it. However, had I only had to use the int foo(char* x),
this never would've been an error because the only place my IDE
could've found that function was from the body definition, which
would've been conveyed accurately. Since it is in two places, we are
again back to the four-action truth table (RR,RW,WR,WW) rather than
the two-action variety (R,W).
One can certainly imagine some non-C language in which declarations
need not precede reference to functions, as long as the declaration
appears *somewhere*. And you may be able to get away with pretending
that you're programming in such a language if your pre-C99 compiler
doesn't enforce the C99 rules. But it will not detect argument
mismatch errors.

Any self-respecting C compiler purposed on recognizing those resources
which exist in computer hardware in the year 2013 should produce the
same code with or without forward declarations provided you are compiling
C source files in a C project. There should never be any discrepancies.

When you are dealing with external things ... that's just the cost of
doing business (external prototype declarations, not forward prototype
declarations).
C certainly allows you to be sloppy. That's why discipline is so
important.

That, and an IDE which is able to point out potential issues as by
compiler-generating warnings. The two should be cojoined.
As for what you can do in some language other than C, perhaps of
your own invention, I frankly do not care.

Well, I appreciate your input on all of this. I realize I am using
the wrong words a lot with regards to C word usage. I apologize.
However, the concepts I'm conveying are, to my knowledge, accurate.

Best regards,
Rick C. Hodgin
 
I

Ian Collins

Rick said:
Only if the function is used.

No, read that again: "Any ".c" file that either defines..". Always
include the header with the prototype declaration in the source file
with the function definition.
So now I'm spending time copy-and-pasting something an intelligent
compiler would otherwise be capable of knowing for itself?

Alas, compilers aren't psychic yet.
Not in this case. I did follow that convention, but the compiler had
no way of reconciling the two because the function was never used.

If it was never used, you wouldn't have had a problem with it, would
you? Don't you consider defining a function "use"? If you had followed
the convention, the definition would have cased an error.
You have misunderstood. I do believe by the time you read this line
that you will have understood my particular case, but I will explain
it plainly just in case.

Somewhere I forward declared:

That somewhere should have been in a header included everywhere the
function was called or defined. End of problem.
 
B

BartC

Ben Bacarisse said:
Why forward? In the brave new world, the compiler is multi-pass. They
can surely all be at the end of a source file just as well as anywhere
else.

Not in gcc 4.8.1. I've tried putting those forward declarations at the end
of the source file, and they don't work down there!
This is getting out of hand. We have no idea at all about what RDC is,
so how can we speculate? If it has run-time types there's no need for
any compiler-time type checking. We are in the dark.

The best we can do is consider something "based on C" that is an
incremental change. If it has compile-time type-checking of function
calls, then something is needed for those cases when the source of the
function being called is not available, or when it is in some language
that RDC can't type-check. That seems to mean that "forward
declarations" can't be eliminated.

I think there's some confusion here. I'm trying to separate C as it is,
which needs these extra declarations, and something else (OK forget RDC
because I don't know the details).

That something else does *not* need the programmer to provide those extra
declarations. It might need them for its internal workings, but it sorts
that out for itself.

(In my case, through external tools, and translators of a modified version
of the language. Example (if you can excuse my introducing some non-C source
to illustrate, this is quite a thick syntax wrapper around C, but the idea
would work with C syntax too):

Input source, defining two functions, one exported and one local:

global function add(int a,b)int=
return a+b
end

function sub(int a,b)int=
return a-b
end

C source file generated (with some manual tidying):

#define global

/* Function Prototypes */

global int add(int a,int b);
static int sub(int a,int b);

/* Local Function Definitions */

global int add(int a,int b) {
return (a+b);
}

static int sub(int a,int b) {
return (a-b);
}

And the corresponding header file:

extern int add(int a,int b);

So three declarations generated from the definitions. The original only
needs the definitions.)
 
K

Keith Thompson

Rick C. Hodgin said:
That is what I did. However, I had not yet used the file. So, as far
as the compiler knew they were two separate functions, but since neither
was referenced it just removed them from the output, or compiled them as
they were and since nothing called them they were ignored.

When I used the function in my code my usage corresponded to the forward
prototype definition. However, the linker could not find that function
because it did not exist. I had to reconcile the issue between my
forward declaration and my function definition. And at that point it
became a research project to figure out which one was correct. It
didn't take long, but it took a minute. The function definition was
correct and I changed the prototype and it worked. That occurred on
four functions actually IIRC, and they were all ** and * variances as
I had changed the code at one point but didn't change the forward
prototype.


Only if the function is used.

No; see below.
So now I'm spending time copy-and-pasting something an intelligent
compiler would otherwise be capable of knowing for itself? "Manual
effort exerted by every use to maintain an outdated standard" is
what it sounds like to me.

It's a way of collecting information needed by client code in one place
(the header file containing function *declarations*) and information
needed to implement the interface in another place (the .c file
containing function *definitions*. There are languages that don't
separate these things. For that matter, strictly speaking, C doesn't
require this kind of organization either, but it's a common convention.

Personally, I find this separation to be useful. I don't need to see,
or even have a copy of, the file containing the definition of a function
to be able to call it.

I'm sure a tool could be written that would take a .c file containing a
set of function definitions, and automatically generate a corresponding
..h file. I'd be quite surprised if such a tool doesn't already exist.
Not in this case. I did follow that convention, but the compiler had
no way of reconciling the two because the function was never used.


You have misunderstood. I do believe by the time you read this line
that you will have understood my particular case, but I will explain
it plainly just in case.

Somewhere I forward declared:

int foo(char** x);

And in my code I wrote the function:

int foo(char* x) { // Code goes here }

I did not call foo() anywhere in my code. As such, the compiler saw
the forward prototype and the function body and logically created two
separate functions internally. But, since none of them were called
it simply discarded them. An error in code, but no way the compiler
could catch it. However, had I only had to use the int foo(char* x),
this never would've been an error because the only place my IDE
could've found that function was from the body definition, which
would've been conveyed accurately. Since it is in two places, we are
again back to the four-action truth table (RR,RW,WR,WW) rather than
the two-action variety (R,W).

Were the "forward" declaration and the function definition in two
separate files?

Suppose you have the declaration:

int foo(char** x);

in foo.h, and the definition:

int foo(char* x) { /* Code goes here */ }

in foo.c. Then foo.c should have a line:

#include "foo.h"

and the compiler, when compiling foo.c, will see the two conflicting
declarations and report the error -- regardless of whether you've
written any calls to foo. (You'd want include guards in foo.h as well.)
Any self-respecting C compiler purposed on recognizing those resources
which exist in computer hardware in the year 2013 should produce the
same code with or without forward declarations provided you are compiling
C source files in a C project. There should never be any discrepancies.

Any conforming C compiler (for C99 or later) must issue a diagnostic
message for any function call for which there is no visible declaration
*preceding* the call.

Prior to C99, calls to functions with no visible declaration were
permitted -- but they were not required to be checked. The compiler
would simply *assume*, without reference to any actual definition, that
the called function returns an int and takes arguments of the (promoted)
types given by the call.

This particular change in C99 was IMHO a substantial improvement to the
language, not in any sense a step backwards (though it did break some
existing legal, but IMHO poorly styled, code).

What you seem to be advocating is a different change to the language,
allowing function declarations and calls to appear out of order and
still be checked. (Is that about right?) Neither pre-1999 C nor
post-1999 C supports this feature. (I personally am not thrilled about
the idea, since we have ways to avoid the need for out-of-order
declarations.)

I'm not trying to convince you that this is the best possible language
design, or that this is the way C *should* be defined. I'm simply
telling you how C *is* defined.
 
B

Ben Bacarisse

BartC said:
Not in gcc 4.8.1. I've tried putting those forward declarations at the end
of the source file, and they don't work down there!

Right. I take it the "!" means joke?

I think there's some confusion here. I'm trying to separate C as it is,
which needs these extra declarations, and something else (OK forget RDC
because I don't know the details).

That something else does *not* need the programmer to provide those extra
declarations. It might need them for its internal workings, but it sorts
that out for itself.

Yes, internals are irrelevant.
(In my case, through external tools, and translators of a modified version
of the language. Example (if you can excuse my introducing some non-C source
to illustrate, this is quite a thick syntax wrapper around C, but the idea
would work with C syntax too):

Input source, defining two functions, one exported and one local:

global function add(int a,b)int=
return a+b
end

function sub(int a,b)int=
return a-b
end

So what has that to do with my point?

<snip>
 
J

James Kuyper

On 01/29/2014 05:16 PM, Rick C. Hodgin wrote:
....
Somewhere I forward declared:

int foo(char** x);

Keep in mind that the convention Keith describes does not merely require
that the forward declaration occur "somewhere". It requires specifically
that it occur at file scope, in a header file, and that the header file
be #included at file scope, into the same translation unit where foo()
is defined, and prior to that definition.

Did you actually follow that convention? Almost certainly not, if you
didn't get a diagnostic message from the following definition of foo():
And in my code I wrote the function:

int foo(char* x) { // Code goes here }

I did not call foo() anywhere in my code. As such, the compiler saw
the forward prototype and the function body and logically created two
separate functions internally.

No - the forward function declaration and the function definition both
declared 'foo' as an identifier with external linkage. The C language
only allows a single thing to be identified by any given identifier with
external linkage. If the definition of the function occurred inside the
scope of the forward declaration (which it would have been, had you
actually been following the convention that Keith describes), then they
must identify the same function, and therefore should have compatible
definitions. They don't, and a conforming implementation of C MUST
therefore issue at least one diagnostic message. It doesn't matter
whether or not there are any calls to the function, anywhere in the
entire program. It's still a constraint violation for which a diagnostic
is mandatory.
Any self-respecting C compiler purposed on recognizing those resources
which exist in computer hardware in the year 2013 should produce the
same code with or without forward declarations provided you are compiling
C source files in a C project. There should never be any discrepancies.

Any self-respecting C compiler will have a mode fully conforming to the
requirements of at least one version of the C standard. For all but the
very first version of that standard, a diagnostic message is mandatory
for any call to any function for which there is no declaration in scope.
After issuing the diagnostic, an implementation is free to conform to
your expectations described above. It's also free to start playing
"Moonlight Sonata" - since the behavior is undefined. However, I think
that you'll find most implementations will halt translation of your
program, so you can fix the problem and restart the process.
When you are dealing with external things ... that's just the cost of
doing business (external prototype declarations, not forward prototype
declarations).

In C as currently defined, "forward" is just a description of the
position of the declaration in the translation unit, relative to the
first use of that declaration. Any prototype declaration with external
linkage that is in the correct position in the translation unit to
qualify as a solution to this problem IS also a forward declaration. You
may be thinking of a relevant distinction, but "external prototype
declaration" and "forward prototype declaration" do not describe
distinct things; you'll need to find different words to describe that
distinction.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top