L
lawrence.jones
In comp.lang.c.moderated Richard Delorme said:Forward function declaration should be added to my list of things to remove.
Then how do you propose to support mutually recursive functions?
In comp.lang.c.moderated Richard Delorme said:Forward function declaration should be added to my list of things to remove.
Rod Pemberton said:Keith Thompson said:Rod Pemberton said:[...]
If I were
redesigning the switch statement from scratch, you'd be able to
specify multiple values in a single case, the "break" keyword
would not be required, and there would probably be special syntax
to specify falling through to the next case.
That works. It's not my first choice though. It just transposes the
locations where one must add additional control flow. E.g., "break;" is
removed, while, say, "fallthru;" is added. It's much like rewriting a
loop with "break's" to use "continue's" instead.
Except that "fallthrough;" (yes, I'd insist on spelling it correctly)
would be much rarer than "break;" is in current C code. Make the
normal case the default, and require a little extra work for the
exception. Of course it's too late to change this in C, unless we
leave the switch statement alone and add a new form of selection
statement (something I'm not advocating).
[...]
It also imposes an arbitrary ordering on the cases and restricts
which cases can fall through to which other cases.
What about "recase" or "reswitch"? E.g., perhaps like so:
case 0x10: recase (0x30);
case 0x20: /* stuff */
break;
case 0x30: /* stuff */
break;
The advantage is you don't need a goto label. The ordering can be as one
wishes. And, each case could then be auto-break. Hmm, that's not too bad,
IMO.
Well, you'd accept that they are C-subset compilers... since they don't
have those keywords. But, they're still C compilers.
Ron Cain's SmallC and variants
(1980, PC, no auto, static, extern, register, double, or float)
Lutz Hamel's WCC
(1987, VMS, no auto, static, extern, register, or double, has float)
Sigh.. Ok, you never post code.
You could've done so to demonstrate
whatever you're getting at.
But, you always want others to do so, so that
you can pick their's apart. Fine, here's one of many possible "Hello
World!" programs in C:
#include <stdio.h>
#include <stdlib.h>
#define HW "Hello World!\n"
int main(void)
{
FILE *out;
char ch;
out=tmpfile(); /* ANSI wb+ */
fprintf(out,HW);
rewind(out);
while(1)
{
ch=getc(out);
if(feof(out))
break;
putchar(ch);
} /* because I could... */
exit(EXIT_SUCCESS);
}
The code works for MS-DOS with multiple compilers (ASCII CRLF as newline).
It works for 64-bit Linux with GCC (ASCII LF as newline). I can't test
MAC's (non-x86 Mac's had ASCII CR as newline), nor EBCDIC (EBCDIC NL as [snip]
PDP-11, or whatever...
C'mon? Who cares?
Really! C is only *so* portable anyway (30% IMO).
Personally, I only have need of C programs working for ASCII, x86, DOS,
Linux.
(I.e., why do I or anyone else for that matter care if it's portable if it
works on an x86 PC? It's the _dominant_ computing platform. I don't have
access to IBM systems or mainframes. I no longer have access to
miniframes, or VMS. So, I can't test the code on them, nor can I fix found
issues. Most other people don't have access either. So, if the compiler
warnings don't catch it, then it's "portable"...)
This is the one side of the coin. In practice, all [str|mem]cpy and
friends can be used securely.
This is the other side of the usability vs security tradeoff. Since
strlcpy() imposes an additional precondition (on size) which strncpy()
does not, and has no way to verify it, it doesn't offer anything in
security terms. It may be easier to use (turning that two-line
"strncpy and NUL terminate" into one) but it is meaningless from a
security point of view.
Not that I am advocating the change, but Java has been dealing with such
things since the beginning. I fail to see why it would be so difficult
for a "C" compiler to do the same.
how?!
How would mutual recursion work? Or separate compilation? What about
those weird people who put main() at the beginning of their
compilation units?
[...]
without forward declarations how is the compiler to deal with that?
Not that I am advocating the change, but Java has been dealing with such
things since the beginning. I fail to see why it would be so difficult
for a "C" compiler to do the same.
Can you compile java files separately and then distribute the
object files, linking them together all willy-nilly?
Yes. Now try this if all you have are a declaration and a precompiled
library.
Then how do you propose to support mutually recursive functions?
Richard Delorme said:Le 16/03/2010 16:47, Nick Keighley a écrit :
Well it already works in other languages like java, caml, etc. And it
almost already works in C:
Here is an example: [snip]
This code contains no forward function declaration, two compilation
units, compiles and produces a working executable with an existing C
compiler. The diagnosis it prints out is also interesting, as it
proves the compiler knows the right declaration format of standard
functions without the need of #include & forward declaration.
Of course, I cheat a little by using an int as return type (if you
replace all 'int' by 'double' and 'atoi' by 'atod' the above code will
still compile but won't work as expected). When seeing an undeclared
function, gcc considers it as a function returning int and decipher
its arguments from its usage (except for variadic functions, as shown
by the diagnosis message). So it works mostly by accident. But I don't
think much work is necessary to make it works in other cases (with
functions not returning int).
Le 05/03/2010 18:56, Casey Hawthorne a écrit :
While reading this thread, it looks that some people want to make
additions to the language, like Jacob Navia's operator overloading &
generic containers. To make the language simpler, or cleaner, why not
rather remove things from it. For example :
- void can be removed from the language. So instead of declaring
void f(void);
we can simply write :
f();
The generic pointer type (void *), could then be replaced by (char*)
without much harm.
- auto can be removed from the language.
- register can be removed from the language. The only thing it is
usefull is to prevent the usage of the address of a variable. If we do
not want to use an address of a variable I think we can refrain
ourselves from doing so, without the need of a keyword. Some compiler
can do some better optimizations with it, but I think most of recent
compilers don't really care of the presence of this keyword.
- restrict can be removed. It is mostly here to facilitate some
optimizations by the compiler by preventing aliases. I think this is not
the duty of the programmer to facilitate optimization, but rather the
burden of the compiler.
- -> operator can be replaced by the . operator.
We can also get further by cleaning the names of basic types. I would
prefer to spell char b.y.t.e., as it makes its purpose more obvious.
Some integer types are redundant, short/int or int/long or long/long
long depending on the machine. I think such redundancy should go.
Obviously the standard library could be improved, at least by removing
dangerous function like gets() or stupid functions like strncpy and
making all functions thread safe. It might also be made simpler by
removing useless type like size_t.
Richard Delorme said:Le 16/03/2010 16:52, Richard Bos a écrit :
Right now it won't work because in absence of a return type, a C
compiler uses the type int as a return type. The above function is in
fact correct and
three() { return 3; }
is the same as
int three() { return 3; }
Now suppose a new standard or a new language that changes this
behaviour so that, in the absence of a type, the compiler uses the
type void. What is the problem ? To me the unnatural behaviour is to
return an int when nothing is written, instead of returning void.
Richard Delorme said:Le 16/03/2010 17:28, (e-mail address removed) a écrit :Then how do you propose to support mutually recursive functions?
like this :
/* file recurse.c */
/*------8<--------------*/
int f(int a)
{
if (a <= 1) return 1;
else return g(a + 2);
}
int g(int b)
{
if (b >= 5) return 5;
return f(b - 1);
}
int main()
{
int i;
for (i = 0; i < 5; ++i) {
printf("f(%d) = %d\n", i, f(i));
printf("g(%d) = %d\n", i, g(i));
}
return 0;
}
/*------8<--------------*/ [snip]
So it is obviously not a problem to implement this as existing
compilers can deal with it.
Nick Keighley said:this being completely unprecedented in the C language
i = i * 2;
f = f * 2.0;
t = *tp;
Willem said:Rod Pemberton wrote:
) What about "recase" or "reswitch"? E.g., perhaps like so:
)
) case 0x10: recase (0x30);
) case 0x20: /* stuff */
) break;
) case 0x30: /* stuff */
) break;
)
) The advantage is you don't need a goto label. The ordering can be as one
) wishes. And, each case could then be auto-break. Hmm, that's not too bad,
) IMO.
I would prefer the 'see' keyword, and I would then recommend pointing back
to earlier cases: It
case 0x10: /* stuff */
break; /*
case 0x20: /* Other stuff */
break;
case 0x30: see case 0x10;
Oh come on, it's too funny not to do it![]()
It's rare for programming language discussion to cause a genuine LOL
moment, but that was one.
However, it's inappropriate for C.
It should be:
case 0x30: static case 0x10;
Even considering only systems using CR, CR/LF, or LF, C's text mode can go
wrong: reading in a file created on a computer with a different newline
sequence, or writing a text file on this computer and reading it on one
using a different sequence.
And then there are hybrid files which are mainly binary data, but also
contain embedded text that can include newline characters. Which means that
binary data that looks like CR/LF gets converted to LF (and the entire file
shrinks in size by one byte), or vice versa.
I suspect people who advocate text mode tend to use machines with a single
character newline, and simply don't see the problems it creates when newline
is multiple characters.
How would a person do it? You've given us a hint here, but placing square.c
next to main.c, so I'm assuming the square() in that file is the one in
question.
The compiler of main.c will need some extra information, such as the names
of some files to search for names which are undefined in main.c. And without
namespaces, it may have to search all the files suggested. In practice it
will likely build a database of exports from those files to speed things up.
The question you haven't asked, is how mutually recursive functions, one in
each of two modules (or perhaps in a circular chain of modules), are
handled. I'm still thinking about that one...
Even considering only systems using CR, CR/LF, or LF, C's text mode can go
wrong: reading in a file created on a computer with a different newline
sequence, or writing a text file on this computer and reading it on one
using a different sequence.
And then there are hybrid files which are mainly binary data, but also
contain embedded text that can include newline characters. Which means that
binary data that looks like CR/LF gets converted to LF (and the entire file
shrinks in size by one byte), or vice versa.
I suspect people who advocate text mode tend to use machines with a single
character newline, and simply don't see the problems it creates when newline
is multiple characters.
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.