Post by Ertugrul SöylemezI thought it would be funny to try to bring functional concepts into the
C language. If anyone is interested, I have published the results on my
blog [1].
[1] http://blog.ertes.de/2008/11/obscure-c-from-new-perspective.html
Of the four programs you posted, three of them depend on a
non-standard extension, namely nested function definitions. As such,
they are, in my opinion, examples of using function concepts in a
C-like language (namely GNU C), not in C itself. (I wonder if similar
things could be done using only standard C -- but I don't wonder
enough to spend a whole lot of time thinking about it.)
If you think that these three programs are an argument in favor of
adding features to C itself, then comp.std.c would be the best place
to make that argument. I offer no opinion (at least for now) on
whether it would be a good idea.
Going back to the first program, it is in standard C, but some of the
coding is quite obscure. For example, in one place you write:
puts("_Expecting one argument.\0Invalid integer." + jv);
where jv has been set to either 1 or 25 in a call to longjmp. Some
other problems I found:
Your factorial function is declared to return an int, but it doesn't
return a value, and the call doesn't attempt to use the returned
value. (The result is returned via longjmp().)
You use the atoi() function, which invokes undefined behavior for
certain arguments.
Your variable names are unnecessarily terse. You use the name "p"
both for a static int in the factorial function, and for a jmp_buf.
If you want to illustrate an unconventional technique, I think it's
best to make the rest of the code as clear as possible.
Here's my version of your program:
/* Factorial function using continuations in C.
* Copyright (C) 2008, Ertugrul Söylemez
* Modified by Keith Thompson
*/
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
enum error_code {
no_error,
bad_arg_count,
invalid_integer
};
static char *errors[] = {
/* no_error (unused) */ NULL,
/* bad_arg_count */ "Expecting one argument.\n",
/* invalid_integer */ "Invalid integer.\n"
};
void factorial(int x, jmp_buf err, jmp_buf print) {
static int product;
jmp_buf recurse;
int jv;
product = 1;
if (x < 0) longjmp(err, invalid_integer);
jv = setjmp(recurse);
if (!jv) longjmp(recurse, x);
product *= jv;
if (jv > 1) longjmp(recurse, jv-1);
longjmp(print, product);
}
int main(int argc, char **argv) {
jmp_buf err;
jmp_buf print;
int jv;
int x;
char *endptr;
jv = setjmp(err);
if (jv) {
fputs(errors[jv], stderr);
return EXIT_FAILURE;
}
jv = setjmp(print);
if (jv) {
printf("%d\n", jv);
return 0;
}
if (argc != 2) {
longjmp(err, bad_arg_count);
}
x = strtol(argv[1], &endptr, 10);
if (argv[1][0] != '\0' && *endptr == '\0') {
factorial(x, err, print);
}
else {
longjmp(err, invalid_integer);
}
}
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"