When did K&R function declarations become obsolete?

8

88888 Dihedral

I think 1995 sounds about right.


Don't worry, there's no chance of that. :) It's just that there is a
new option to disable K&R header parsing - this parsing can be
inordinately slow, for example when there are long sequences of variable
declarations (which might be K&R parameter specifications). It's a shame
to impose this performance penalty on everybody, just because of some
obsolete construct which "nobody" uses any more.

In a standard C compiler, a line can be very very long and the number of
arguments allowed in a C function is nearly free style.

OK, this is a good environment for those who want to write obfuscated
programs easily.
 
A

Alan Mackenzie

James Kuyper said:
I think we can say that K&R function declarations are truly obsolete. In
~20 years of hacking C, I've only seen very old code which uses them.
Presumably these declarations are still widely used in compiler validation
suites but nowhere else.
Approximately when did they become obsolete, i.e. not used at all for new
code?
[Context: I'm writing documentation for Emacs's C Mode.]
For me personally, non-prototype declarations became (almost) obsolete
as soon as I learned about prototypes, which was shortly after the C
standard was first published. However, many people write code to
standards which require portability to compilers that pre-date the C
standard, even though their code no longer needs to be ported to such
compilers, and hasn't needed such porting for a decade or more.
Therefore, I doubt that they have yet become obsolete in the sense that
you define: "not used at all for new code".

Interesting! I don't think I'd like to work in a shop like that, though.
Also, there's still one point where non-prototype function declarations
are useful. Try to declare a prototype for a function taking, as an
argument, a pointer to a function of the SAME type. You'll quickly
discover that the declaration recurses infinitely.

A fine academic exercise, sure, but is there any practical use of such a
declaration? It sounds like something you'd really want a functional
programming language to do.
Somewhere along the way, you have to terminate it. There's a number of
ways to terminate it, but the simplest is to use a non-prototype
declaration that leaves the number and type of the parameters
unspecified.

Won't the judicious use of "void *" for the parameter do the trick?
Other methods, in principle, run into type compatibility
issues if the pointer is actually used to call a function whose
definition uses the same prototype.

Thanks for this idea.
 
J

James Kuyper

Interesting! I don't think I'd like to work in a shop like that, though.

Me neither. I'm an early adopter (but unlike ralph, I'm not a
pre-adopter). I adopted the new features of C90 as soon as I knew I
could use a compiler that supported them. I would have done the same for
C99, if the coding standards imposed on our project by our client
allowed it - which they (still!) do not.
A fine academic exercise, sure, but is there any practical use of such a
declaration? It sounds like something you'd really want a functional
programming language to do.

I first ran into this issue in the context of signal handlers, but I
don't remember the details well enough to allow you to evaluate the
practicality of the design. It was a standard library (not the C
standard library) function heavily used by a great many other people, so
I presume it wasn't just an academic exercise for them. However, I've
never written programs for which signal handling was needed, which is
why I don't remember the details.

There's a similar issue with declaring a function that returns a pointer
to a function of the same type.
Won't the judicious use of "void *" for the parameter do the trick?

No, void* and function pointer types are not compatible.
 
A

André Gillibert

Alan Mackenzie said:
A fine academic exercise, sure, but is there any practical use of such a
declaration? It sounds like something you'd really want a functional
programming language to do.


Won't the judicious use of "void *" for the parameter do the trick?

Something like:
typedef int (*recfunc_type)(int (*func)(void));

int recfunc(int (*func)(void))
{
/* ... */
((recfunc_type)func)(func);
/* ... */
}

This should work, as the function pointer is eventually converted to
the correct data type.
 
8

88888 Dihedral

Something like:
typedef int (*recfunc_type)(int (*func)(void));

int recfunc(int (*func)(void))
{
/* ... */
((recfunc_type)func)(func);
/* ... */
}

This should work, as the function pointer is eventually converted to
the correct data type.

Wrap the input functor to a some other functor.
I don't use typedef too often.
Also this will lead to the question:
If there are failures in using a functor due to some I/O or OS services,
what error messages can be thrown and what function to catch these kinds of
failures?
 
A

André Gillibert

88888 Dihedral said:
Wrap the input functor to a some other functor.
I don't use typedef too often.
Also this will lead to the question:
If there are failures in using a functor due to some I/O or OS services,
what error messages can be thrown and what function to catch these kinds of
failures?

How does that lead to this question?
 
B

Ben Bacarisse

Keith Thompson said:
The first ANSI C standard was issued in 1989, not 1986. Are you
referring to something else that happened in 1986?

Several websites refer to a Draft Proposed Standard issued sometime
around 1985/86 intended to gave implementers a "heads up". The only one
I can recall was a sort of final draft issued in 1988, after noalias was
nixed. If there was a widely distributed draft in 85/86 it would be
very interesting see it.
I know that the C community was eager to see the new ANSI C standard,
and that part of were implemented before the standard itself was
released. I don't have a clear idea of what the time scale was.

I seem to recall K&R saying that the code in K&R II was tested using
cfront (early C++) because an ANSI compiler was not available at the
time (probably 1987 since the book came out in 1988).

Maybe they were unaware of compilers that Ralf was aware of in the PC
world. Of course, no 1985 compiler can be "ANSI C" in the technical
sense, but as a result of good guessing and guidance from having people
on the committee it's just possible they exactly anticipated the
eventual standard.

<snip>
 
B

Ben Bacarisse

Alan Mackenzie said:
It's just that there is a
new option to disable K&R header parsing - this parsing can be
inordinately slow, for example when there are long sequences of variable
declarations (which might be K&R parameter specifications). It's a shame
to impose this performance penalty on everybody, just because of some
obsolete construct which "nobody" uses any more.

Can you expand on this? I can't see why it would be particularly slow.
You description hints at some hard to resolve ambiguity with old-style
function declarations.
 
8

88888 Dihedral

Several websites refer to a Draft Proposed Standard issued sometime
around 1985/86 intended to gave implementers a "heads up". The only one
I can recall was a sort of final draft issued in 1988, after noalias was
nixed. If there was a widely distributed draft in 85/86 it would be
very interesting see it.


I seem to recall K&R saying that the code in K&R II was tested using
cfront (early C++) because an ANSI compiler was not available at the
time (probably 1987 since the book came out in 1988).

Maybe they were unaware of compilers that Ralf was aware of in the PC
world. Of course, no 1985 compiler can be "ANSI C" in the technical
sense, but as a result of good guessing and guidance from having people
on the committee it's just possible they exactly anticipated the
eventual standard.

<snip>

That was the Pascal and Fortran era in 198x.
There are p2c and f2c available, thus a lot people just switched programming
in C.

But nowadays the 3rd generation of programming language is somewhat
not going anywhere in developing artificial intelligent systems.
 
B

Ben Bacarisse

Alan Mackenzie said:
James Kuyper <[email protected]> wrote:

A fine academic exercise, sure, but is there any practical use of such a
declaration? It sounds like something you'd really want a functional
programming language to do.

Similar things crop up naturally in some state machine implementations
but It's certainly not common.
Won't the judicious use of "void *" for the parameter do the trick?

So will using int, or any other type! void * does not help directly
(because function pointers don't convert to and from void *) but it
won't hurt. Unless the parameter can be declared directly, a cast is
needed at the point of call to convert the function pointer, whose type
we have effectively lied about, to the correct type.

Using an old-stlye function pointer type has the advantage of being a
bit clearer:

int function(int (*fp)(), int);

is less of a lie than simply picking a type for fp's first parameter.
If you use old-style declarations (and definitions) all the way, then
you don't need a cast at all, but you do lose all type-checking.

<snip>
 
R

ralph

Several websites refer to a Draft Proposed Standard issued sometime
around 1985/86 intended to gave implementers a "heads up". The only one
I can recall was a sort of final draft issued in 1988, after noalias was
nixed. If there was a widely distributed draft in 85/86 it would be
very interesting see it.

I attended a local committee meeting I believe in 1986. Might have
been 1987 <???>. (Ghod I hate getting old. <g>) At that time I paid, I
think, ~$50 for a cheap bound "draft". The youngsters might find it
hard to believe amount of paper we used back then. Digital media was
rare, and often in some obscure format when it was available. <g>

I'm such a pack rat I might still have it boxed up someplace, I'll go
and try to find it.
I seem to recall K&R saying that the code in K&R II was tested using
cfront (early C++) because an ANSI compiler was not available at the
time (probably 1987 since the book came out in 1988).

Maybe they were unaware of compilers that Ralf was aware of in the PC
world. Of course, no 1985 compiler can be "ANSI C" in the technical
sense, but as a result of good guessing and guidance from having people
on the committee it's just possible they exactly anticipated the
eventual standard.

<snip>

Well we were talking about "ANSI style" declarations and prototypes. I
know those features were available with MSC 3.0, the compiler was
generally considered "ANSI compatible", and was in wide-use by 1985.
But I agree with you - there is absolutely NO way it could have been
fully C89 compilant. There were still minor compliancy issues with MSC
5/6 and they were released AFTER C89.

[I remember the discussions and complaints, but not the details. As
I've already noted - I'm no language lawyer. Nor do I have much
patience for those who quarrel over which IMHO is minutia. <g>]

I don't know what particular ANSI features K&R might have considered
as 'unavailable'. But given the climate of the day and the target
audience, I'm positive NO limited platform compiler would have been
considered "suitable" for such a book.

-ralph
 
R

ralph

The first ANSI C standard was issued in 1989, not 1986. Are you
referring to something else that happened in 1986?

I know that the C community was eager to see the new ANSI C standard,
and that part of were implemented before the standard itself was
released. I don't have a clear idea of what the time scale was.

Yeah, that was a bit of misdirection on my side. Thanks for catching
that. I was trying to piece together a time scale in my mind while I
was typing. <g>

I remembered attending a local "J Committee" meeting in 1986 (and two
more after - 87???), and was going to offer the fact that we were
predominately arguing over what current implementations should appear
in the eventual standard as evidence that much of "ANSI stuff" was
already in common use. But my memory is just too foggy. Can't supply
vendor names or versions (except for Microsoft) so I decided to skip
going down that road. But I had "1986" stuck in my brain as the year
when we started thinking about "ANSI".
[...]
The "-noalias" option was one of the latter ideas. Don't know if I
ever used a compiler that offered that keyword. I only know I never
used it. I vaguely remember it as an optimizing option, but believe it
applied to whole code blocks not to any one variable.

We're not talking about a "-noalias" option. Early drafts
of the ANSI C standard include a "noalias" keyword. (I think
C99's "restrict" keyword is a redesigned version of the concept.)
Dennis Ritchie posted his opinion of it in this newsgroup in March
1988 <http://www.lysator.liu.se/c/dmr-on-noalias.html>:

Noalias must go. This is non-negotiable.

It must not be reworded, reformulated or reinvented. The draft's
description is badly flawed, but that is not the problem.
The concept is wrong from start to finish. It negates
every brave promise X3J11 ever made about codifying existing
practices, preserving the existing body of code, and keeping
(dare I say it?) `the spirit of C.'

[...]

Yes I know the noalias suggestion was a keyword. The original question
was if I remembered ever using that keyword. My answer was no, but
vaguely remember there being the compiler option back then.

Ritchie sums it up for most of the fights and distinctly illustrates
what I considered emphasizing in my previous post - most of what
eventually became "standardized" in the ANSI Standard was already in
common "existing practice" before C89.

At least that is how I remember it, but seeing Mr. Sosman's and Mr.
Becarisse's posts it is now obvious that was not that "common" for
everyone and has been rather enlightening. Previous to their posts I
would have scoffed at the notion that any shop was still adhering to a
"K&R C Standard" by 1990. Can't do that now. <g>

-ralph
 
K

Keith Thompson

James Kuyper said:
Also, there's still one point where non-prototype function declarations
are useful. Try to declare a prototype for a function taking, as an
argument, a pointer to a function of the SAME type. You'll quickly
discover that the declaration recurses infinitely. [...]
Somewhere along the way, you have to terminate it. There's a number of
ways to terminate it, but the simplest is to use a non-prototype
declaration that leaves the number and type of the parameters
unspecified.

Won't the judicious use of "void *" for the parameter do the trick?

No, void* and function pointer types are not compatible.

But the language guarantees that converting any function pointer
to another pointer-to-function type and back again yields the original
pointer. That means you can use *any* pointer-to-function type (the
simplest is "void (*)(void)") as a generic pointer-to-function type.
 
J

Joe keane

ralph said:
But I had "1986" stuck in my brain as the year when we started thinking
about "ANSI".

Sounds about right, where everyone agreed on the meaning and most
current compilers accept it [of course you can find old/not updated
compilers].

Add another ten years for it to be more prevalent.

Is it similar for:

definitely have 'void'
can pass and return 'struct'

?
 
E

Eric Sosman

ralph said:
But I had "1986" stuck in my brain as the year when we started thinking
about "ANSI".

Sounds about right, where everyone agreed on the meaning and most
current compilers accept it [of course you can find old/not updated
compilers].

There was, of course, a risk in jumping the gun: You might build
a feature in accordance with a working draft, only to see the final
Standard make changes. Something of this sort certainly happened with
C99: The gcc folks had implemented some features that the C99 Standard
chose to do differently.
Add another ten years for it to be more prevalent.

Is it similar for:

definitely have 'void'

Speaking for myself, I didn't see `void' widely used until after
ANSI was adopted. But then, the code I was involved with at the time
was running on five platforms with ports in progress for a sixth and
seventh; we didn't want to adopt anything new until we were sure it
would work on all our targets. Uptake may have been more rapid in
monoculture environments.

`void*' (as opposed to plain `void') started to appear in our
code fairly early, because it was easy to `typedef char void;' for
compilers that didn't have it. True, the resulting `char*' would
not convert silently to other pointer types -- but the compilers
that didn't have `void*' already required casts anyhow, so the ruse
was "mostly harmless."
can pass and return 'struct'

Again speaking for myself, we did this freely in pre-ANSI days;
the capability had come into general use not long after the K&R book.
We used enums freely, too (they're also absent from K&R).
 
E

Eric Sosman

But the language guarantees that converting any function pointer
to another pointer-to-function type and back again yields the original
pointer. That means you can use *any* pointer-to-function type (the
simplest is "void (*)(void)") as a generic pointer-to-function type.

"void (*)()" is even simpler -- which gets us back to the
thread's original topic ;-)
 
K

Keith Thompson

Eric Sosman said:
"void (*)()" is even simpler -- which gets us back to the
thread's original topic ;-)

It's shorter by one token and 4 letters. But I'd say that "pointer to
function with no parameters and returning no result" is *conceptually*
simpler than "pointer to function with an unspecified but fixed number
and type(s) of parameter(s) and returning no result".
 
N

Nick Keighley

That was the Pascal and Fortran era in 198x.
There are p2c and f2c available, thus a lot people just switched programming
in C.

I don't think p2c and f2c had much influence (I was looking for
CORAL66toc myself)
But nowadays the 3rd generation of programming language


how do you count generations?

1. FORTRAN, COBOL, ALGOL, LISP
2. Pascal, Occam, Ada, C, C++
3. Java, Perl, Python, Ruby, C#

where do Scheme, Snobol, Haskell, Prolog go?
is somewhat
not going anywhere in developing artificial intelligent systems.

was that a goal of Java or Ruby? Or Pascal or FORTRAN?

Another way to count generations is

1. patch panels and valves
2. machine code
3. Fortran (and everything else including Java)
4. Cobol code generators (where are they now?)
5. That Japanese project to write everything in Prolog that no one
remembers now.
 
A

Alan Mackenzie

Can you expand on this? I can't see why it would be particularly slow.
Your description hints at some hard to resolve ambiguity with old-style
function declarations.

Certainly. There's a lisp function c-in-knr-argdecl which determines
whether the current position is inside a K&R section. It basically
searches back over (what look like) variable declarations till it comes
to a ')' which isn't followed by a ';'. It then performs some extra
checks. If there is no such ')' but large numbers of variable
declarations, c-in-knr-argdecl could be searching an awful long way. To
counteract this danger, there is an arbitrary limit (20) on the number of
parameters. Even with this limit, things can get a bit sluggish.
 
B

Ben Bacarisse

Alan Mackenzie said:
Certainly. There's a lisp function c-in-knr-argdecl which determines
whether the current position is inside a K&R section. It basically
searches back over (what look like) variable declarations till it comes
to a ')' which isn't followed by a ';'. It then performs some extra
checks. If there is no such ')' but large numbers of variable
declarations, c-in-knr-argdecl could be searching an awful long way. To
counteract this danger, there is an arbitrary limit (20) on the number of
parameters. Even with this limit, things can get a bit sluggish.

Sorry, I'd forgotten the context -- I though you were saying that it was
slow to parse in the normal sense.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top