complex declarations

R

Robbie Brown

I have the following code

/* declare signal as function (int, pointer to function (int) returning
void) returning pointer to function (int) returning void */

void (*signal(int, void (*)(int)) ) (int);

/* simplify things a bit using a typedef */
typedef void (*fptr)(int);

int main(void){

/* declare and define function that takes int and returns void */
void foobar(int x){
printf("%s%d\n", "x in foobar is ", x);
}

/* define signal using the typedef, compiles */
fptr signal(int x, fptr y){
return NULL;
}

/* What I'd like to do now is to replace the fptr typedef with the
pre typedef type if that makes sense.
Why? because it helps my understanding */

/* Here I can say, void y(), void (y)(), void (*y)(), void y(int),
void(y)(int) void (*y)(int) for the second arg and they all
compile */

fptr signal2(int x, void (*y)(int) ){
NULL;
}

/* finally I want to do something like
return a pointer to a function taking int and returning void
but I just can't figure out how to do it. I've tried
void (*)(int), void (int), (void (*) (int)) etc etc without
success */

/* can't get this to compile in any way */
//void (*x) (int) signal3(int x, void (*y)(int) ){
// return NULL;
//}

}


How do I code signal3 to completely get rid of my dependence on the
typedef. Once again, the only reason I want to do this is because I can
(hopefully)

Thanks
 
J

James Kuyper

I have the following code

/* declare signal as function (int, pointer to function (int) returning
void) returning pointer to function (int) returning void */

void (*signal(int, void (*)(int)) ) (int);

/* simplify things a bit using a typedef */
typedef void (*fptr)(int);

int main(void){

This location is inside the block associated with main.
/* declare and define function that takes int and returns void */
void foobar(int x){
printf("%s%d\n", "x in foobar is ", x);
}

C function definitions can only occur at file scope (6.9p1). You can
declare a function at block scope (6.8p2), but you can't define it
there. Because you can't define it with block scope, I also personally
feel it's a bad idea to declare it at file scope - but that's just a
personal preference, not a C rule.

If you got this code to compile (except for the part you're asking
about), then you're taking advantage of a non-conforming extension to C
which allows block scope definitions of functions. If making use of that
extension is important to you, then you should post your questions to a
forum specializing in the particular compiler that supports that
extension. If it supports that extension, it may support others, and
advice that you get from this newsgroup might be useless for that compiler.
/* define signal using the typedef, compiles */
fptr signal(int x, fptr y){
return NULL;
}

/* What I'd like to do now is to replace the fptr typedef with the
pre typedef type if that makes sense.
Why? because it helps my understanding */

/* Here I can say, void y(), void (y)(), void (*y)(), void y(int),
void(y)(int) void (*y)(int) for the second arg and they all
compile */

fptr signal2(int x, void (*y)(int) ){
NULL;
}

/* finally I want to do something like
return a pointer to a function taking int and returning void
but I just can't figure out how to do it. I've tried
void (*)(int), void (int), (void (*) (int)) etc etc without
success */

/* can't get this to compile in any way */
//void (*x) (int) signal3(int x, void (*y)(int) ){

That's because you start out declaring an identifier named x to be a
pointer to a function taking an argument of type int. Then you try to
follow that up with the declaration of signal3. You can declare the name
of a function and the names of it's arguments, but you can't declare a
name for the value returned by that function. What you want to do is to
declare signal3 as returning an UNNAMED pointer to a function taking one
argument of type int.
// return NULL;
//}

}


How do I code signal3 to completely get rid of my dependence on the
typedef. Once again, the only reason I want to do this is because I can
(hopefully)

How do you make the pointer returned by signal3 unnamed? You have to use
a type name, which syntactically looks just like the declaration of an
identifier of a function or an object, except that it omits the identifier.

void (*)(int) signal3(int x, void(*y)(int))

Type names are also used in casts and sizeof() expressions. In C99,
they're also used in compound literals. In C2011, they're also used in
_Generic() associations, _Alignof() expressions, _Atomic() type
specifiers, and _Alignas() specifiers.
 
J

James Kuyper

On 03/04/2014 03:49 PM, James Kuyper wrote:
,,,
C function definitions can only occur at file scope (6.9p1). You can
declare a function at block scope (6.8p2), but you can't define it
there. Because you can't define it with block scope, I also personally
feel it's a bad idea to declare it at file scope - but that's just a

"file" should have been "block" in that last sentence. That error almost
exactly reverses my intended meaning.

....
Type names are also used in casts and sizeof() expressions. In C99,
they're also used in compound literals. In C2011, they're also used in
_Generic() associations, _Alignof() expressions, _Atomic() type
specifiers, and _Alignas() specifiers.

I should also mention that function declarations are allowed to use type
names for the parameters; you're only required to name the parameters in
the function definition itself. This is not stated directly by the use
of the phrase "type name", but only implicitly by the fact that 6.7.6p1
does not require a parameter-declaration to contain a declarator, it can
use an abstract-declarator instead. That freedom is retracted for
function definitions (6.9.1p5).
 
B

Ben Bacarisse

Robbie Brown said:
I have the following code

/* declare signal as function (int, pointer to function (int)
returning void) returning pointer to function (int) returning void */

void (*signal(int, void (*)(int)) ) (int);

/* simplify things a bit using a typedef */
typedef void (*fptr)(int);

int main(void){

/* declare and define function that takes int and returns void */
void foobar(int x){
printf("%s%d\n", "x in foobar is ", x);
}

Nested functions are an extension. The fact that your code compiles
means you are not using the compiler in its strictest mode. When you
are trying to understand things, it helps to get the compiler to tell
you as much a possible and using this extension prevents you from doing
that.
/* define signal using the typedef, compiles */
fptr signal(int x, fptr y){
return NULL;
}

/* What I'd like to do now is to replace the fptr typedef with the
pre typedef type if that makes sense.
Why? because it helps my understanding */

/* Here I can say, void y(), void (y)(), void (*y)(), void y(int),
void(y)(int) void (*y)(int) for the second arg and they all
compile */

fptr signal2(int x, void (*y)(int) ){
NULL;
}

/* finally I want to do something like
return a pointer to a function taking int and returning void
but I just can't figure out how to do it. I've tried
void (*)(int), void (int), (void (*) (int)) etc etc without
success */

/* can't get this to compile in any way */
//void (*x) (int) signal3(int x, void (*y)(int) ){
// return NULL;
//}

}

How do I code signal3 to completely get rid of my dependence on the
typedef. Once again, the only reason I want to do this is because I
can (hopefully)

You gave the declaration of such a function right at the top of the post:

void (*signal(int, void (*)(int)) ) (int);

To convert the declaration to a definition, give the parameters names
and replace the ';' with the function body.
 
B

BartC

Ben Bacarisse said:
You gave the declaration of such a function right at the top of the post:

void (*signal(int, void (*)(int)) ) (int);

To convert the declaration to a definition, give the parameters names
and replace the ';' with the function body.

Which ones are the parameters?!

(I ran this with CDECL (http://www.lemoda.net/c/cdecl/index.cgi) which was
only mildly helpful, even after I varied the ints a bit so I could see which
was which.

I /think/ the first parameter name goes after the first int, and the second
one after the * in (*).)
 
R

Robbie Brown

C function definitions can only occur at file scope (6.9p1). You can
declare a function at block scope (6.8p2), but you can't define it
there. Because you can't define it with block scope, I also personally
feel it's a bad idea to declare it at file scope - but that's just a
personal preference, not a C rule.

If you got this code to compile (except for the part you're asking
about), then you're taking advantage of a non-conforming extension to C
which allows block scope definitions of functions.

I used gcc -std=c99 complexdecl.c and you are right. Apparently the
ability to define a function within a function (nesting of functions) is
a gcc extension, sheesh, you really gotta be on the ball with this stuff
haven't you?

That's because you start out declaring an identifier named x to be a
pointer to a function taking an argument of type int. Then you try to
follow that up with the declaration of signal3. You can declare the name
of a function and the names of it's arguments, but you can't declare a
name for the value returned by that function. What you want to do is to
declare signal3 as returning an UNNAMED pointer to a function taking one
argument of type int.


How do you make the pointer returned by signal3 unnamed? You have to use
a type name, which syntactically looks just like the declaration of an
identifier of a function or an object, except that it omits the identifier.

void (*)(int) signal3(int x, void(*y)(int))

That was one of the first things I tried and for some reason that
(obviously) escapes me it doesn't compile.

So, I simplified the code, now I have (with emacs line no's)

3. void (*signal(int, void (*)(int)) ) (int);
4.
5. void (*) (int) sig(int x, void (*y)(int) ){
6. return NULL;
7. }
8.
9. int main(void){
10.
11. }

I used gcc -std=c99 complexdecl.c

Compilation failed with
complexdecl.c:5:8: error: expected identifier or ‘(’ before ‘)’ token

5:8 is just after the leftmost ) in the definition.
Just for a laugh I tried with sig nested inside main and still failure.
I have also tried -std=gnu99 as I noticed that that can do some weird
stuff.

Like I say, one of the first things I tried was
void (*) (int) sig(int x, void (*y)(int) ) and I was surprised
that it didn't compile.

Obviously I'm missing something here but I don't really know what to try
next. Any ideas much appreciated.

Thanks


--
Rob - not floundering, fishing
========================================================
For every SCoP we generate the polyhedral representation
and transform it back to gimple.
========================================================
Seems perfectly reasonable to me.
 
R

Robbie Brown

Nested functions are an extension. The fact that your code compiles
means you are not using the compiler in its strictest mode. When you
are trying to understand things, it helps to get the compiler to tell
you as much a possible and using this extension prevents you from doing
that.


You gave the declaration of such a function right at the top of the post:

void (*signal(int, void (*)(int)) ) (int);

To convert the declaration to a definition, give the parameters names
and replace the ';' with the function body.


OK, I did this and ... it compiles, now my brain hurts

void (*signal(int x, void (*i)(int y)) ) (int z){
return NULL;
}

I just can't see how the above and

typedef void (*fptr)(int);

fptr signal (int x, fptr);

which also compiles are equivalent

What a headbanger.


--
Rob - not floundering, fishing
========================================================
For every SCoP we generate the polyhedral representation
and transform it back to gimple.
========================================================
Seems perfectly reasonable to me.
 
K

Keith Thompson

Robbie Brown said:
I used gcc -std=c99 complexdecl.c and you are right. Apparently the
ability to define a function within a function (nesting of functions) is
a gcc extension, sheesh, you really gotta be on the ball with this stuff
haven't you?

Use "gcc -std=c99 -pedantic" to make it warn about violations of the C99
standard. gcc is not a conforming C compiler without the "-pedantic"
option. Use "-pedantic-warnings" to turn those warnings into fatal
errors.
 
J

James Kuyper

I used gcc -std=c99 complexdecl.c and you are right. Apparently the
ability to define a function within a function (nesting of functions) is
a gcc extension, sheesh, you really gotta be on the ball with this stuff
haven't you?

If you add "-pedantic" to "-std=c99", you will have eliminated most of
your dependence on gcc extensions, though I personally would recommend
adding "-Wall -Wpointer-arith -Wcast-align -Wstrict-prototypes
-Wmissing-prototypes" as well. Other people like to turn on several
additional warnings, particularly -Wextra, but I find a lot of those
warnings to be spurious.

<snip incorrect advice from my previous message, except for final
recommendation:>
....
That was one of the first things I tried and for some reason that
(obviously) escapes me it doesn't compile.

That's because I managed to get confused during the process of
responding to you. I put a lot of effort into making that message
complete; I should have put a bit more effort into making it correct. A
simple test compile would have reminded me of my error, and I would have
known how to correct it, but I didn't do such a test.

Ben's answer is the correct one, and it renders irrelevant everything I
said about type names. It was all correct (I think), except for the part
about a type name being the answer to your problem. :-(
 
J

James Kuyper

On 03/04/2014 04:59 PM, Robbie Brown wrote:
....
OK, I did this and ... it compiles, now my brain hurts

void (*signal(int x, void (*i)(int y)) ) (int z){

This has the form
LEFT_PART signal(int x, void (*i)(int y)) RIGHT_PART {

What I've called LEFT_PART and RIGHT_PART are what define the return
type. The rest of the declaration names the function that has that
return type, and declares its arguments.
return NULL;
}

I just can't see how the above and

typedef void (*fptr)(int);

This has the form

typedef LEFT_PART fptr RIGHT_PART;

Where LEFT_PART and RIGHT_PART are the same as in the previous
declaration. Here, it only declares a type, which is the same as the
return type of signal().
fptr signal (int x, fptr);

which also compiles are equivalent

Does that explanation help?
 
B

Ben Bacarisse

BartC said:
Which ones are the parameters?!

void (*signal(int signum, void (*newaction)(int)) ) (int);
(I ran this with CDECL (http://www.lemoda.net/c/cdecl/index.cgi) which was
only mildly helpful, even after I varied the ints a bit so I could see which
was which.

I /think/ the first parameter name goes after the first int, and the second
one after the * in (*).)

Yes. How can one tell? Well, signal is a function because its name is
followed by an (. That ( starts the comma separated list of parameters
that ends with the matching ). I.e. this is the parameter list:

int, void (*)(int)

It's clear where the first name goes. The second is a little harder but
we know it's a pointer parameter and pointer types always have a * to
the immediate left of the name. There's only one place to put a name so
that it has a * immediately on to the left.
 
B

Ben Bacarisse

Robbie Brown said:
OK, I did this and ... it compiles, now my brain hurts

void (*signal(int x, void (*i)(int y)) ) (int z){
return NULL;
}

That's it, but you don't need the names for things that are not
parameters to the function (after all, the function's body can only
refer to its two parameters):

void (*signal(int x, void (*i)(int)) ) (int) ...

(and I'd use other names -- x and i are rather minimal!)
I just can't see how the above and

typedef void (*fptr)(int);

fptr signal (int x, fptr);

which also compiles are equivalent

What a headbanger.

Yes, it takes some time to get your head round all this.

There are two substitutions to here:

fptr signal(int x, fptr f)

The inner one is simple: you put "f" where the typedef'd name is in

typedef void (*fptr)(int);

(removing the "typedef" keyword and the ; of course):

fptr signal(int x, void (*f)(int))

To do the first one, let's go back to the simpler form:

fptr signal(int x, fptr f)

The key part to know is that you can't separate a function's name from
it parameter list. Just substituting the function name ("signal") in
the definition of the return type (void (*fptr)(int)) breaks this link:

void (*signal)(int)(int x, fptr f) // WRONG!

This now looks like a function that takes a single int. The trouble is
that the function includes it's parameters -- we need to substitute
"signal(int x, fptr f)" into the defined type:

void (*fptr)(int)
^
put signal(int x, fptr f) in here:

void (*signal(int x, fptr f))(int)

Now we can go back and do the other one as well to get the final full
type:

void (*signal(int x, void (f)(int)))(int)

Simples!

No, I know it's far from simple. Of course, most people go the other
way: simplifying a type by defining simpler parts of the type.
Complicating a simplified type, is just for learning.

This might help: http://bsb.me.uk/c-types
 
R

Robbie Brown

That's it, but you don't need the names for things that are not
parameters to the function (after all, the function's body can only
refer to its two parameters):

void (*signal(int x, void (*i)(int)) ) (int) ...

(and I'd use other names -- x and i are rather minimal!)


Yes, it takes some time to get your head round all this.

There are two substitutions to here:

fptr signal(int x, fptr f)

The inner one is simple: you put "f" where the typedef'd name is in

typedef void (*fptr)(int);

(removing the "typedef" keyword and the ; of course):

fptr signal(int x, void (*f)(int))

To do the first one, let's go back to the simpler form:

fptr signal(int x, fptr f)

The key part to know is that you can't separate a function's name from
it parameter list. Just substituting the function name ("signal") in
the definition of the return type (void (*fptr)(int)) breaks this link:

void (*signal)(int)(int x, fptr f) // WRONG!

This now looks like a function that takes a single int. The trouble is
that the function includes it's parameters -- we need to substitute
"signal(int x, fptr f)" into the defined type:

void (*fptr)(int)
^
put signal(int x, fptr f) in here:

void (*signal(int x, fptr f))(int)

Now we can go back and do the other one as well to get the final full
type:

void (*signal(int x, void (f)(int)))(int)

Simples!

Yes, or no. No, but I think I get it.
I almost hesitate to ask this but shouldn't that be

void (*signal (int x, void (*f) (int)))(int);

as opposed to

void (*signal (int x, void (f) (int)))(int);
^ should be func pointer

Or am I still missing something?

Excellent explanation BTW

<snip>


--
Rob - not floundering, fishing
========================================================
For every SCoP we generate the polyhedral representation
and transform it back to gimple.
========================================================
Seems perfectly reasonable to me.
 
R

Robbie Brown

Use "gcc -std=c99 -pedantic" to make it warn about violations of the C99
standard. gcc is not a conforming C compiler without the "-pedantic"
option. Use "-pedantic-warnings" to turn those warnings into fatal
errors.

OK, well my gcc doesn't support -pedantic-warnings.

However

-pedantic warns and still produces an executable
-pedantic-errors produces an error message and does not produce an
executable, so I guess it's the same difference.

It's a bit of a minefield though isn't it?

Now I know there's no such thing but
Does the 'average C developer' actually need to know all this all the
time or do people often/sometimes 'specialize' in a particular compiler
implementation along with it's extensions?

Thanks for the reply


--
Rob - not floundering, fishing
========================================================
For every SCoP we generate the polyhedral representation
and transform it back to gimple.
========================================================
Seems perfectly reasonable to me.
 
B

Ben Bacarisse

Robbie Brown said:
On 05/03/14 00:28, Ben Bacarisse wrote:
There are two substitutions to [do] here:

fptr signal(int x, fptr f)

The inner one is simple: you put "f" where the typedef'd name is in

typedef void (*fptr)(int);

(removing the "typedef" keyword and the ; of course):

fptr signal(int x, void (*f)(int))
Now we can go back and do the other one as well to get the final full
type:

void (*signal(int x, void (f)(int)))(int)

Simples!

Yes, or no. No, but I think I get it.
I almost hesitate to ask this but shouldn't that be

void (*signal (int x, void (*f) (int)))(int);

as opposed to

void (*signal (int x, void (f) (int)))(int);
^ should be func pointer

Or am I still missing something?

No, you are quite correct. I copied the text wrongly (it's right in the
first example and got messed one in the final one).
Excellent explanation BTW

Thank you.
 
R

Robbie Brown

On 03/04/2014 03:49 PM, James Kuyper wrote:
,,,

"file" should have been "block" in that last sentence. That error almost
exactly reverses my intended meaning.

OK, I suppose I'm pushing my luck here but I'm not entirely sure what
you are saying so here goes

If I have a 'program' foo.c that (tries to) comply with some seemingly
nebulous set of rules that are apparently defined in the latest spec I
can find 'for free' (n1256.pdf) then I can't have nested functions for
one thing. So, where exactly should I define my functions?

If I have an 'all in one file program' then I don't need function
prototypes and I declare and define all my sub-functions, that is
functions that are not main() at the top of the file, once, and use them
in main(). I'd call this 'file scope'.

I can also declare prototypes at the top of the file and define the
functions after the end of main() although why I'd want to do this I
have no idea. Also 'file scope'

I can also declare prototypes at the head of main or in an include file
and define them somewhere else. What scope is this? It's obviously more
flexible to have a func.h and func.c dedicated 'function container' as
it allows easy reuse.

There are other questions, like, where's the sanity of declaring a
prototype in block scope when you can't define it in same (this seems
particularly bizarre)

I'm trying to come up with a sane 'standard approach' to partitioning my
code. I don't expect an answer as I'm not even sure of the question but
it's good to get it off my chest :)


--
Rob - not floundering, fishing
========================================================
For every SCoP we generate the polyhedral representation
and transform it back to gimple.
========================================================
Seems perfectly reasonable to me.
 
J

James Kuyper

OK, well my gcc doesn't support -pedantic-warnings.

I'm pretty sure that was a typo for -pedantic-errors
However

-pedantic warns and still produces an executable
-pedantic-errors produces an error message and does not produce an
executable, so I guess it's the same difference.

I don't usually bother with -pedantic-errors, but there is a real
benefit to using it: if there is no executable, you can't be tempted to
try executing it.
It's a bit of a minefield though isn't it?

Now I know there's no such thing but
Does the 'average C developer' actually need to know all this all the
time or do people often/sometimes 'specialize' in a particular compiler
implementation along with it's extensions?

Most people specialize in some way - my personal choice was to
specialize in writing to the C standard, avoiding compiler-specific
extensions, but that's mainly because my company's client has imposed a
strong portability requirements on our code. You should be able to
compile and successfully execute our code on any system with sufficient
memory and disk space that supports POSIX (1003.1, IIRC) and C95. you
might have to make minor modifications to the make file, but you
shouldn't have to do anything to the source code to make it work. I
avoid even depending upon POSIX unless necessary. Some of my code relies
on POSIX's guarantee that CHAR_BIT == 8; but most of it would continue
to work properly even if that weren't true.

People writing code that has weaker portability requirements can and
usually do justify learning more about the quirks of a particular
compiler than I ever have.
 
B

BartC

Robbie Brown said:
OK, I suppose I'm pushing my luck here but I'm not entirely sure what you
are saying so here goes

If I have a 'program' foo.c that (tries to) comply with some seemingly
nebulous set of rules that are apparently defined in the latest spec I can
find 'for free' (n1256.pdf) then I can't have nested functions for one
thing. So, where exactly should I define my functions?

You define one after the other in the file. But not one inside the other.
If I have an 'all in one file program' then I don't need function
prototypes and I declare and define all my sub-functions, that is
functions that are not main() at the top of the file, once, and use them
in main(). I'd call this 'file scope'.

Without prototypes, you need to define functions in a certain order such
that a function is always defined before it is called. But that's not always
possible.
I can also declare prototypes at the top of the file and define the
functions after the end of main() although why I'd want to do this I have
no idea. Also 'file scope'

Because you (and people maintaining your code who are not familiar with the
call-tree) then have total freedom in editing the code, moving blocks
around, chopping things up, pasting from elsewhere, etc. Otherwise you have
to spend some effort in making sure that all functions are in a particular
order.

But, if any of your functions are exported to another module, then you will
need to produce prototypes for that module anyway. (Actually all C functions
are exported unless you declare them with 'static'. You can also call them
from elsewhere without a prototype; that's how C used to work. These days
prototypes for exported/imported functions are a good idea.)
I can also declare prototypes at the head of main or in an include file
and define them somewhere else. What scope is this? It's obviously more
flexible to have a func.h and func.c dedicated 'function container' as it
allows easy reuse.

There are other questions, like, where's the sanity of declaring a
prototype in block scope when you can't define it in same (this seems
particularly bizarre)

That can work for an 'extern' function defined in another module and
declared for use here. It would
be unusual though to want to restrict its visibility to just that function
(or even that block).
I'm trying to come up with a sane 'standard approach' to partitioning my
code. I don't expect an answer as I'm not even sure of the question but
it's good to get it off my chest :)

This is C. There isn't a standard approach.
 
J

James Kuyper

OK, I suppose I'm pushing my luck here but I'm not entirely sure what
you are saying so here goes

If I have a 'program' foo.c that (tries to) comply with some seemingly
nebulous set of rules that are apparently defined in the latest spec I
can find 'for free' (n1256.pdf) then I can't have nested functions for
one thing. So, where exactly should I define my functions?

At file scope, in as many or as few different files as you like.
If I have an 'all in one file program' then I don't need function
prototypes and I declare and define all my sub-functions, that is
functions that are not main() at the top of the file, once, and use them
in main(). I'd call this 'file scope'.

I can also declare prototypes at the top of the file and define the
functions after the end of main() although why I'd want to do this I
have no idea. Also 'file scope'

Some people (not including myself) prefer that approach because they
consider it more logical.
I can also declare prototypes at the head of main or in an include file
and define them somewhere else. What scope is this?

That depends upon what you mean by "head of main", and where you
#include the header file:

bar.h:
#ifndef H_BAR
#define H_BAR
int bar(int);
#endif

foo.h:
#ifndef H_FOO
#define H_FOO
void foo();
#endif

main.c:
// Is this what you mean by "head of main"?
// create a file scope declaration for bar():
#include "bar.h"
int file_scope_declaration(double);

int main()
{
// Or is this what you mean by "head of main"?
// NB: I do NOT recommend block scope function declarations
double block_scope_declaration(int);
// Create block scope declaration for foo()
#include "foo.h"
// Do NOT do this with any standard header - the behavior is
// undefined (7.1.2p4).

foo();

return bar(file_scope_declaration(block_scope_declaration(0));
}

There are other questions, like, where's the sanity of declaring a
prototype in block scope when you can't define it in same (this seems
particularly bizarre)

While I agree with you about that, those who disagree with us say that
by doing so, they're limiting the scope of the prototype, reducing the
danger of naming conflicts.
 
J

James Kuyper

....
But, if any of your functions are exported to another module, then you will
need to produce prototypes for that module anyway. (Actually all C functions
are exported unless you declare them with 'static'. You can also call them
from elsewhere without a prototype; that's how C used to work. These days
prototypes for exported/imported functions are a good idea.)

Note to Robbie: Bartc is primarily interested in designing his own
language, and uses the term "export" to describe a feature of that
language. This term has no well-defined meaning in C. C functions have
external linkage unless declared 'static', in which case they have
internal linkage. However, they cannot be called from another
translation unit without a declaration in scope in that translation
unit. The declaration should be a prototype, but that's not required by
the language.

In C90, if a previously undeclared identifier was used as if it were a
function, a declaration was implicitly created for that identifier as
the name of a function returning an int and taking a fixed but
unspecified number of arguments of unspecified types. This was found to
be a very error-prone feature - it was removed in C99.
 

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

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top