FAQ 1.12--auto keyword

B

Bill Pursell

The faq (question 1.12) states that the keyword "auto" is completely
useless.
However, it is necessary to forward declare a nested function (for
gcc...I'm not sure if this is gcc specific or a language issue.)
In other words:

int
main(void)
{
AUTO int foo(void);
return 0;

int foo (void)
{
return 0;
}
}

is valid only if AUTO is "auto" and not empty. Is this a language
issue, or is allowing the forward declaration a gcc extension?
If a language issue, should the FAQ be modified?
 
S

Skarmander

Bill said:
The faq (question 1.12) states that the keyword "auto" is completely
useless.
However, it is necessary to forward declare a nested function (for
gcc...I'm not sure if this is gcc specific or a language issue.)

It's gcc specific. Nested functions are not part of the language proper.
Standard C does not allow function declarations to nest.
In other words:

int
main(void)
{
AUTO int foo(void);
return 0;

int foo (void)
{
return 0;
}
}

is valid only if AUTO is "auto" and not empty. Is this a language
issue, or is allowing the forward declaration a gcc extension?

Nested functions as a whole are a gcc extension, let alone forward declaring
them.
If a language issue, should the FAQ be modified?
It's not, and a note in the FAQ would not be wise, IMO, as this gets too
specific.

S.
 
K

Keith Thompson

Bill Pursell said:
The faq (question 1.12) states that the keyword "auto" is completely
useless.
However, it is necessary to forward declare a nested function (for
gcc...I'm not sure if this is gcc specific or a language issue.)
In other words:

int
main(void)
{
AUTO int foo(void);
return 0;

int foo (void)
{
return 0;
}
}

is valid only if AUTO is "auto" and not empty. Is this a language
issue, or is allowing the forward declaration a gcc extension?
If a language issue, should the FAQ be modified?

Standard C doesn't allow nested function definitions.

gcc could have told you this:

% gcc -c -ansi -pedantic -DAUTO=auto tmp.c
tmp.c: In function `main':
tmp.c:4: warning: invalid storage class for function `foo'
tmp.c:8: warning: ISO C forbids nested functions
tmp.c:10: warning: ISO C90 forbids mixed declarations and code

(Same thing with "-std=c99", except that the last warning doesn't
show up.)
 
S

Skarmander

Skarmander said:
It's gcc specific. Nested functions are not part of the language proper.
Standard C does not allow function declarations to nest.
That should be "definitions". A function declaration is allowed within a
function, although this is generally not done.

S.
 
R

Richard Bos

Bill Pursell said:
The faq (question 1.12) states that the keyword "auto" is completely
useless.
However, it is necessary to forward declare a nested function (for
gcc...I'm not sure if this is gcc specific or a language issue.)

There is no such thing as a nested function in ISO C.

If gcc allows nested functions, that's its business. However, if it
requires "auto" to forwardly declare them, this is broken. They should
have chosen "static".

Richard
 
B

Bill Pursell

Richard said:
There is no such thing as a nested function in ISO C.

If gcc allows nested functions, that's its business. However, if it
requires "auto" to forwardly declare them, this is broken. They should
have chosen "static".

Actually, I'm thinking the entire nested function idea is broken. When
I first saw it, I thought it was a neat idea, but I quickly changed my
impression of it to "interesting curiosity". I now consider it
completely pointless. But it does raise a question for me.

If I want to get the same behavior as a nested function (and as
far as I can tell, all it gives you is the ability to have 2 different
functions with the same name in the same linkage unit), I
could do this:

#include <stdio.h>

static int
func0(int x)
{
return x;
}

static int
func1(int x)
{
return x +1;
}

static int
foo0(int x)
{
static int(*const func)(int) = func0;
return func(x);
}

static int
foo1(int x)
{
static int(*const func)(int) = func1;
return func(x);
}

int
main(void)
{
printf("%d\n", foo0(0));
printf("%d\n", foo1(0));
}

So both foo0() and foo1() can use the name "func" to
reference different functions. Now, my question is:
is this as efficient as coding it so that foo{i} calls func{i}
directly? It seems like there may be any extra step involved.
Is there a way I could code it so that the two are certainly
identical? I'm declaring each as const within foo to
try to make that happen, but I suspect it doesn't really
help.
 
K

Keith Thompson

Bill Pursell said:
Actually, I'm thinking the entire nested function idea is broken. When
I first saw it, I thought it was a neat idea, but I quickly changed my
impression of it to "interesting curiosity". I now consider it
completely pointless. But it does raise a question for me.

If I want to get the same behavior as a nested function (and as
far as I can tell, all it gives you is the ability to have 2 different
functions with the same name in the same linkage unit), I
could do this:
[snip]

In languages that support them, nested functions have visibility to
declarations in their parent functions.
 
V

Vladimir S. Oka

Bill Pursell opined:
Actually, I'm thinking the entire nested function idea is broken.
When I first saw it, I thought it was a neat idea, but I quickly
changed my impression of it to "interesting curiosity". I now
consider it completely pointless. But it does raise a question for
me.

If I want to get the same behavior as a nested function (and as
far as I can tell, all it gives you is the ability to have 2
different functions with the same name in the same linkage unit)

Well, it gives you the ability to have functions that are visible only
in their outer function and nowhere else. IMHO, that has it's uses
(does Pascal background start to show?). Whether this feature should
be introduced in C, or whether it is a "must have", is a completely
different issue (IMHO, answer to both is no).

--
The face of war has never changed. Surely it is more logical to heal
than to kill.
-- Surak of Vulcan, "The Savage Curtain", stardate 5906.5

<http://clc-wiki.net/wiki/Introduction_to_comp.lang.c>
 
M

Michael Wojcik

That should be "definitions". A function declaration is allowed within a
function,

provided it does not use the "static" storage-class specifier,[1]
although this is generally not done.

Partly because the (mysterious) prohibition against the use of
"static" in this context means you can't declare a function at block
scope correctly if the function has internal linkage. Largely,
though, it's because it's not especially useful; it could potentially
be used to help a maintainer keep track of which functions are called
from which other functions, assuming a sufficiently verbose
implementation, but there are generally better ways of doing that.


1. C99 6.7.1 #5
 
M

Michael Wojcik

There is no such thing as a nested function in ISO C.

If gcc allows nested functions, that's its business. However, if it
requires "auto" to forwardly declare them, this is broken. They should
have chosen "static".

That's debatable. I think "auto" is more appropriate, since it
suggests the additional work necessary to provide the called nested
function with a link to the enclosing function's closure (using a
static chain or display or what have you) as part of its environment.
That, to me, is a more significant feature of nested functions than
their limited scope, which I imagine is what would justify yet
another application of "static".

Though to be honest I think reusing any of the existing keywords was
a bad idea; if they want to invent a new language, they should invent
a new language.

--
Michael Wojcik (e-mail address removed)

You brung in them two expert birdwatchers ... sayin' it was to keep us from
makin' dern fools of ourselfs ... whereas it's the inherent right of all to
make dern fools of theirselfs ... it ain't a right held by you official types
alone. -- Walt Kelly
 
B

Ben Pfaff

Bill Pursell said:
If I want to get the same behavior as a nested function (and as
far as I can tell, all it gives you is the ability to have 2 different
functions with the same name in the same linkage unit), I
could do this:

I once wrote some very nonportable, system- and compiler-specific
code that used GCC's nested function extension. The code is
below. Of course, I haven't included all of the necessary
declarations, etc. Your approach wouldn't allow me to do the
same thing so easily; I would have to pass a lot of arguments
back and forth to plot(), or encapsulate them in a structure, or
duplicate code.

/* Nonportable code that uses extensions. */
void
bogl_vga16_text (int xx, int yy, const char *s, int n, int fg, int bg,
struct bogl_font *font)
{
/* Font height, or possibly less due to clipping. */
int h;
int x, y;
unsigned long bits[font->height];

void plot (void)
{
volatile unsigned char *dst = frame + xx / 8 + yy * bogl_line_len;
int y, i;

for (y = 0; y < h; y++)
{
unsigned long b = bits[y];

for (i = ul_size - 1; i >= 0; i--)
{
set_mask (b);
rmw (dst + i);
b >>= 8;
}

dst += bogl_line_len;
}
}

assert (xx >= 0 && xx < bogl_xres);
assert (yy >= 0 && yy < bogl_yres);

h = font->height;
if (yy + h > bogl_yres)
h = bogl_yres - yy;

if (bg != -1)
{
int x2 = xx + bogl_metrics (s, n, font);
if (x2 >= bogl_xres)
x2 = bogl_xres - 1;

bogl_vga16_clear (xx, yy, x2, yy + h, bg);
}

bogl_drawing = 1;

for (y = 0; y < h; y++)
bits[y] = 0;

set_color (fg);
select_mask ();

x = xx % ul_bits;
xx = xx / ul_bits * ul_bits;

for (; n--; s++)
{
const unsigned char ch = (unsigned char) *s;
const unsigned long *character = &font->content[font->offset[ch]];
const int width = font->width[ch];

for (y = 0; y < h; y++)
bits[y] |= character[y] >> x;
x += width;

if (x >= (int) ul_bits)
{
plot ();

x -= ul_bits;
for (y = 0; y < h; y++)
bits[y] = character[y] << (width - x);

xx += ul_bits;
if (xx >= bogl_xres)
goto done;
}
}
plot ();

done:
bogl_drawing = 0;
}
 
C

CBFalconer

Bill said:
.... snip ...

Actually, I'm thinking the entire nested function idea is broken.
When I first saw it, I thought it was a neat idea, but I quickly
changed my impression of it to "interesting curiosity". I now
consider it completely pointless. But it does raise a question
for me.

If you have ever used Pascal and similar languages you will soon
see the value of it. It allows careful control of scope, for
functions, variables and other things (eg. CONST in Pascal).
Unfortunately the gcc implementation effectively passes an extra
hidden parameter, and simply does not port. It is not necessary,
since you can achieve almost identical control to one nesting level
with multiple source files and some discipline.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
R

Richard Bos

That's debatable. I think "auto" is more appropriate, since it
suggests the additional work necessary to provide the called nested
function with a link to the enclosing function's closure (using a
static chain or display or what have you) as part of its environment.

True; but for logistical reasons, gcc should not have used a keyword
that was existant but previously useless. It leads to confusion. Better
to invent a new one.
That, to me, is a more significant feature of nested functions than
their limited scope, which I imagine is what would justify yet
another application of "static".

Yes, but re-using "static" for purposes only tangentially related to
those it had before is Traditional.
Though to be honest I think reusing any of the existing keywords was
a bad idea; if they want to invent a new language, they should invent
a new language.

I agree. But that would not be as kewl as claiming you've written a C
compiler.

Richard
 
M

Michael Wojcik

If you have ever used Pascal and similar languages you will soon
see the value of it. It allows careful control of scope, for
functions, variables and other things (eg. CONST in Pascal).

Scope is not the only, nor to my mind the more interesting,
consequence of nesting functions.

Nested functions (in any proper implementation) capture their
ancestors' closures. That has potentially complex and interesting
consequences for program design.

Consider a recursive visitor-pattern function, for example - let's
say a function that iterates depth-first over a binary tree and calls
a delegate function at each node.

At the top level we have something like:

void Visit(struct tree *tree, void (*visitor)(struct tree *))
{
if (tree)
{
visitor(tree);
Visit(tree->left, visitor);
Visit(tree->right, visitor);
}
}

But if we have nested functions, we can push the recursion down a
level and hoist the visitor-function parameter out of it:

void Visit(struct tree *tree, void (*visitor)(struct tree *))
{
void Visit_r(struct tree *tree)
{
if (tree)
{
visitor(tree);
Visit(tree->left);
Visit(tree->right);
}
}

Visit_r(tree);
}

That saves us a parameter per recursive call, because Visit_r's
environment includes the current values of Visit's parameters and
local variables.

Now, in the actual implementation, there will likely be a hidden
parameter (as Chuck mentioned) for the static chain, unless the
implementation uses a display or some more esoteric mechanism. But
the nested-function representation is still clearer, as it only
explicitly passes the changing parameter, and if there are multiple
parameters that can be eliminated this way, there's a net savings.

However, C doesn't have nested functions, and adding them is a major
change to the language. There are plenty of programming languages
that *do* have nested functions, so people who want them have that
option. When I want a language with lots of expressive- ness, I use
OCaml or something like that. When I want to work in a tightly-
specified language with minimal black-box magic, I use C.
 
M

Michael Wojcik

Yes, but re-using "static" for purposes only tangentially related to
those it had before is Traditional.

True - Seebs' Principle probably applies to extensions as well as
revisions of the standard. (And there's also Dennis' story of
prenatal new-keyword trauma...)
I agree. But that would not be as kewl as claiming you've written a C
compiler.

I suppose not. There does seem to be (or at least have been) a fair
bit of "133t ski11z" sentiment among the GCC contributors. Could it
be that Stallman encouraged that?

--
Michael Wojcik (e-mail address removed)

As always, great patience and a clean work area are required for fulfillment
of this diversion, and it should not be attempted if either are compromised.
-- Chris Ware
 
M

Mark McIntyre

If you have ever used Pascal and similar languages you will soon
see the value of it.

I've used Pascal, and indeed C++ which allows a similar idea, and
frankly, I can count on the fingers of one foot the number of times
I've needed an entire function to be private to another function. YMMV
of course.

Mark McIntyre
 

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
474,176
Messages
2,570,950
Members
47,503
Latest member
supremedee

Latest Threads

Top