C as a scripting language


J

jacob navia

Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

Setup
-----

The task to be solved is as follows:

In the current directory you have a bunch of .c files.
For each file in that directory you should start the C
compiler, compile the file, and if the compile works,
link it and then run it. You should gather some statistics
about how many runs were done, and how many compilation
errors or run time errors were discovered, printing them
at the end.

Here is a solution using the "ruby" language:
--------------------------------------------------------------
#/usr/bin/ruby -w
class Array
alias :append :push
end

def run_and_collect(file_list)
comp_counter = 0
run_counter = 0
count_all_compilations = 0
failed_compilations = 0
count_all_runs = 0
failed_runs = 0
failed_run_progs = []
successfull_runs = []
failed_compilation_runs = []

file_list.each {|file|
ret_val = system("../lcc -O -DNO_LABEL_VALUES -c -nw -g2
#{file} -o a.obj && gcc a.obj lcclibc_asm.s -o a -lm")
count_all_compilations += 1
if (ret_val == false)
puts("failed compilation: #{file}")
failed_compilations += 1
failed_compilation_runs.append(file)
else
ret_val = true
ret_val = system("./a")
run_counter+= 1
if (ret_val == false)
puts("failed run: #{file}");
failed_runs += 1
failed_run_progs.append(file + " ")
successfull_runs.append(file)
end
end
}
puts("Compilations: #{count_all_compilations}, failed:
#{failed_compilations}\n
Runs: #{run_counter}, failed: #{failed_runs}\n
#{failed_run_progs} \n")
end

run_and_collect(ARGV)
---------------------------------------------------------------------
Now the C solution:
--------------------------------------------------------------------
#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];
int r, tests=0,CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS],*LFailures[MAXTESTS],
*RFailures[MAXTESTS];

f = popen("ls *.c","r");
while (fgets(buf,sizeof(buf),f)) {
char *p = strchr(buf,'\n');
if (p) *p=0;
tests++;
sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);
} else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);
}
}
}
}
pclose(f);
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
if (CompilationFailures) {
printf("Compilation Failures: (%d)\n",CompilationFailures);
ShowFailures(CFailures,CompilationFailures);
}
if (LinkFailures) {
printf("Link failures: (%d)\n",LinkFailures);
ShowFailures(LFailures,LinkFailures);
}
if (RunFailures) {
printf("Run failures (%d)\n",RunFailures);
ShowFailures(RFailures,RunFailures);
}
}

void ShowFailures(char *tab[],int n)
{
for (int i=0; i<n; i++) { printf("%s ",tab); } printf("\n");
}
----------------------------------------------------------------------------

Both programs use identical algorithms:
(1) The list of *.c files will be established. Ruby uses a list, C uses
a pipe connected to another process that sends a line at a time.
(2) For each file the compiler is called, then the linker and the
resulting program. Statistics are gathered.
(3) A printout at the end of the run lists the failures.

The length in source code of both programs is very similar.

The running time of both programs is identical.

I wrote the C program, and a friend wrote the ruby program. It was
for testing the Unix version of lcc-win, i.e. both programs are
used in a "production" setting.

I think that both languages are perfectly equivalent in this example.

The next example I will post is web programming.

Thanks for your attention.
 
Ad

Advertisements

K

Keith Thompson

jacob navia said:
Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

Setup
-----

The task to be solved is as follows:

In the current directory you have a bunch of .c files.
For each file in that directory you should start the C
compiler, compile the file, and if the compile works,
link it and then run it. You should gather some statistics
about how many runs were done, and how many compilation
errors or run time errors were discovered, printing them
at the end.

Here is a solution using the "ruby" language:
-------------------------------------------------------------- [snip]
---------------------------------------------------------------------
Now the C solution:
--------------------------------------------------------------------
#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];
int r, tests=0,CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS],*LFailures[MAXTESTS],
*RFailures[MAXTESTS];

f = popen("ls *.c","r");
while (fgets(buf,sizeof(buf),f)) {
char *p = strchr(buf,'\n');
if (p) *p=0;
tests++;
sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);
} else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);
}
}
}
}
pclose(f);
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
if (CompilationFailures) {
printf("Compilation Failures: (%d)\n",CompilationFailures);
ShowFailures(CFailures,CompilationFailures);
}
if (LinkFailures) {
printf("Link failures: (%d)\n",LinkFailures);
ShowFailures(LFailures,LinkFailures);
}
if (RunFailures) {
printf("Run failures (%d)\n",RunFailures);
ShowFailures(RFailures,RunFailures);
}
}

void ShowFailures(char *tab[],int n)
{
for (int i=0; i<n; i++) { printf("%s ",tab); } printf("\n");
}
----------------------------------------------------------------------------

[snip]

When I compile the above with "lcc -ansic" (using lcc-win), I get:

Warning c.c: 13 missing prototype for popen
Warning c.c: 13 Missing prototype for 'popen'
Error c.c: 13 operands of = have illegal types 'pointer to struct _iobuf' and 'int'
Warning c.c: 21 missing prototype for system
Warning c.c: 21 Missing prototype for 'system'
Warning c.c: 26 sprintf: missing argument for format s
Warning c.c: 27 Missing prototype for 'system'
Warning c.c: 32 Missing prototype for 'system'
Warning c.c: 40 missing prototype for pclose
Warning c.c: 40 Missing prototype for 'pclose'
1 error, 9 warnings

I'm surprised it didn't warn about the missing prototype for strdup.
(And you might want to look into the duplicate warnings for the
missing prototypes.)

Even with those problems corrected, there are a number of system
dependencies in the program. You assume that system() returns 0 if
the invoked command succeeds; the standard says only that the result
is implementation-defined. You assume the existence of an "ls"
command, and of the popen() and pclose() functions.

Perhaps this would be better suited to comp.unix.programmer.
 
J

jacob navia

Keith Thompson wrote:
He wrote that *windows* lcc-win doesn't understand popen...

Obviously I am using Unix lcc-win, that knows about popen
in /usr/include/stdio.h

This would be obvious to anyone but Mr Thompson...
Or maybe he ignores everything about the Unix system,
I do not know.

In any case the point of my message is that using C
is perfectly OK as a scripting language and compres
equal to ruby.

Mr Thompson did not address those issues.
 
J

jacob navia

Keith Thompson wrote:
nonsense

I didn't realize that he called lcc-win wqith
-ansic

that eliminates all non-standard functions like popen.

Of course, when he posts that,

HE IS NOT LYING

and (of course)

HE IS NOT POSTING IN BAD FAITH trying to make
my compiler system in the worst possible light.

HE IS NOT BIASED.

No, of course not!
 
K

Keith Thompson

jacob navia said:
Keith Thompson wrote:
He wrote that *windows* lcc-win doesn't understand popen...

Obviously I am using Unix lcc-win, that knows about popen
in /usr/include/stdio.h

My point was that, in this instance, lcc-win was behaving as a
conforming C compiler should, issuing a warning for a call to the
non-standard popen() function. Note that "gcc -std=c99" also issues a
warning.

A conforming C implementation must allow a user to use the name popen
for his own purposes. If it provides a mode that allows the use of
This would be obvious to anyone but Mr Thompson...
Or maybe he ignores everything about the Unix system,
I do not know.

Correct, you do not know.

Please feel free to address me by my first name, as most people here
do. (I'm not sure whether you're trying to be formal or rude.)

I had actually assumed that popen() was declared in some header other
than <stdio.h>, perhaps <unistd.h>. On checking, I see that POSIX
In any case the point of my message is that using C
is perfectly OK as a scripting language and compres
equal to ruby.

Mr Thompson did not address those issues.

No, I didn't; was I required to?

I'll also note that strdup() is non-standard, that you call system()
without the required "#include <stdlib.h>", and that you have a
missing argument in your sprintf call. The first is just a
portability issue, but the others are actual errors. Did your
compiler not warn you about them?

As for the use of C as a scripting language, I'll just make one
observation. In the C version, you had to pick arbitrary buffer sizes
(512 and 1024 bytes). If an input line overflows the buffer, you
appear to quietly use the truncated buffer, and then read the next
line and process it as if it were a separate line. There are ways to
avoid this in C, but they tend to make the code more verbose with
error checking. Scripting languages typically handle arbitary input
lines much more easily. (And you don't use argc, argv, or tmpbuf.)

If you're not interested in having your errors pointed out, you can
ignore this; others may benefit.

Personally, I'd almost certainly use Perl for a task like this, but
that's just me. For a task for which saving time or space isn't very
important, I find that a scripting language makes things easier, by
freeing me from thinking about things like memory management and
rolling my own data structures.
 
B

Bartc

jacob navia said:
Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

It's not surprising that C can be used for any task.

But the point of scripting languages is to accomplish a task more quickly
and less painfully than using C, where everything has to be just right,
especially the punctuation. And without bothering with compile-link-run as
much.
The length in source code of both programs is very similar.

This is not too surprising. It would be interesting to see Ruby or Python
code from someone who isn't primarily a C programmer.

You've neatly avoided the problems of an unknown number of files in C (by
using a size assumed to be big enough), and you don't have very demanding
string ops.
The running time of both programs is identical.

The running times for programs doing file i/o are going to be comparable.
 
Ad

Advertisements

F

Flash Gordon

jacob navia wrote:

#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>

All headers included are above

void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];

You might want to use fewer magic numbers and get rid of tmpbuf as you
don't use it.

r = system(cmd);

You might want to include stdlib.h for system.
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");

You might want to provide the arguments your format specifier promises.

Both programs use identical algorithms:
(1) The list of *.c files will be established. Ruby uses a list, C uses
a pipe connected to another process that sends a line at a time.

So if that list is part of then that is an advantage for Ruby, since you
are using features that are not part of C.
(2) For each file the compiler is called, then the linker and the
resulting program. Statistics are gathered.

If your C program links the code then it is by chance.
(3) A printout at the end of the run lists the failures.

The length in source code of both programs is very similar.

The running time of both programs is identical.

I wrote the C program, and a friend wrote the ruby program. It was
for testing the Unix version of lcc-win, i.e. both programs are
used in a "production" setting.

<snip>

Then you need to fix your program. Start with fixing all the things the
compiler warns about in it.
 
J

jacob navia

George said:
jacob said:
Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

Setup
----- [snip]
I think that both languages are perfectly equivalent in this example.

The next example I will post is web programming.

Thanks for your attention.

Jacob, there are actually other people that share your view.

The Varnish web cache/accelerator uses VCL as a configuration language, and
then compiles that to C which then is compiled at runtime for use with
Varnish.

There is even an entire operating system where the shell compiles a C-like
language at runtime, and puts the resulting code into Malloc()ed memory.
See: http://www.losethos.com/

Losethos is a one man, six year effort. It's quite interesting from what
I've seen. He wrote his own C-like compiler for that project.

I've also heard of some LISP-like languages that compile to C at runtime,
and then load the resulting object code transparently.

Now, if only C had an eval() these things would be so much easier... :)

-George

Now THAT is an interesting project.

I would like to know more but apparently the download links do not work
with my browser. I will try tomorrow.

Thanks for the link!
 
K

Keith Thompson

jacob navia said:
Keith Thompson wrote:
nonsense

I didn't realize that he called lcc-win wqith
-ansic

that eliminates all non-standard functions like popen.

Of course, when he posts that,

HE IS NOT LYING
Correct.

and (of course)

HE IS NOT POSTING IN BAD FAITH trying to make
my compiler system in the worst possible light.
Correct.

HE IS NOT BIASED.
Correct.

No, of course not!

You're really not good at the sarcasm thing.
 
J

jacob navia

Flash said:
jacob navia wrote:

#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>

All headers included are above

void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];

You might want to use fewer magic numbers and get rid of tmpbuf as you
don't use it.

r = system(cmd);

You might want to include stdlib.h for system.
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");

You might want to provide the arguments your format specifier promises.

This is the only error that creeped in when pasting the code and trying
to reformat it. should be:
obviously



So if that list is part of then that is an advantage for Ruby, since you
are using features that are not part of C.


You do not know what C is dude

[snip drivel]

Obviously the regs here do not understand the purpose of scripting.

Scripting is a quick program, not designed for speed or portability
that fills a task in a production chain. If there are 512 bytes
unused somewhere nobody cares.

By the way, the same code runs under lcc-win under windows. You should
just change the "ls" to "dir /b" and the rest is the same.


ANd I will go on posting code here whenever I feel like it. Other people
(like Gordon) can't do that. He has never posted a single line here.
The same for all other "regs" complaining their usual nonsense.

The are unable to do anything constructive and limit themselves to
pissing around other people.

Well let them do that if they are happy with it.
 
M

Mark Wooding

jacob navia said:
In the current directory you have a bunch of .c files.
For each file in that directory you should start the C
compiler, compile the file, and if the compile works,
link it and then run it. You should gather some statistics
about how many runs were done, and how many compilation
errors or run time errors were discovered, printing them
at the end.

[snip to C version]
#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];
int r, tests=0,CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS],*LFailures[MAXTESTS],
*RFailures[MAXTESTS];

f = popen("ls *.c","r");
while (fgets(buf,sizeof(buf),f)) {

Dereferencing null pointers isn't fun. Let's hope there weren't any
errors setting up that pipe, eh?

This will incorrectly interpret filenames which contain newline
characters as the names of two or more separate files (which may or may
not exist). It will also silently do something wrong on very long file
names (namely to split the file name into 511-byte chunks, with a short
trailing chunk, and treat each chunk as a separate name).

It will also process the files contained within directories matching
`*.c', regardless of the names of the contained files.
char *p = strchr(buf,'\n');
if (p) *p=0;
tests++;
sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);

Buffer overflow here if there are many files. Let's hope there was
enough memory for the string copy.
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);

And again.
} else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);

And... It's like shooting fish in a barrel.
}
}
}
}
pclose(f);

This discards the exit status from `ls'. You'll never know whether it
returned all the files. In fact, you'll never know if you actually had
permission to read the current directory at all.
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
if (CompilationFailures) {
printf("Compilation Failures: (%d)\n",CompilationFailures);
ShowFailures(CFailures,CompilationFailures);

With hilarious results if we stashed a null pointer earlier.
}
if (LinkFailures) {
printf("Link failures: (%d)\n",LinkFailures);
ShowFailures(LFailures,LinkFailures);
}
And...

if (RunFailures) {
printf("Run failures (%d)\n",RunFailures);
ShowFailures(RFailures,RunFailures);
}
}

void ShowFailures(char *tab[],int n)
{
for (int i=0; i<n; i++) { printf("%s ",tab); } printf("\n");
}


Both programs use identical algorithms:
(1) The list of *.c files will be established. Ruby uses a list, C uses
a pipe connected to another process that sends a line at a time.


Actually, the Ruby code doesn't do this at all; it just processes the
files named on its command line.
(2) For each file the compiler is called, then the linker and the
resulting program. Statistics are gathered.

The Ruby version doesn't check separately for link failures: it uses a
shell operator to do both compiling and (if that worked) linking,
without informing the script which part was responsible for any
failures.
(3) A printout at the end of the run lists the failures.

The length in source code of both programs is very similar.

Indeed. The C code is doing things the Ruby code doesn't do. I'll
certainly agree that the programs are commensurate in length.
The running time of both programs is identical.

Unsurprising. Compared to the overheads of running the compiler and
linker, you won't notice even fairly gross inefficiencies in the script.

I'd probably have written the whole thing as a shell script, I must
admit:

#! /bin/sh
set -e
stages="compile link run"
clean () { for i in $stages; do rm -f $i-failures done; }
for i in $stages; do eval n$i=0; done
try () {
set -e
what=$1 name=$2; shift 2
if ! "[email protected]"; then
echo "failed to $what: $name"
eval n$i="\$(expr \$n$i + 1)"
echo "$name" >>$what
fi
}
clean
for f in *.c; do
o=${f%.c}.o
try compile "$f" ../lcc -g2 -nw "$f"
try link "$f" gcc "$o" lcclibc_asm.s -lm
try run "$f" ./a.out
done
for i in $stages; do
if [ -r $i-failures ]; then
eval n=\$n$i
echo "$i failures ($n)"
cat $i-failures
fi
done
clean

Shorter than either, mostly easier to read (apologies for the eval
hacking, though -- I would have used `wc -l' but that loses when file
names contain newlines), with all the features of the C version and none
of the bugs. (Downside: it clobbers some files you're unlikely to have
created.)
I wrote the C program, and a friend wrote the ruby program. It was
for testing the Unix version of lcc-win, i.e. both programs are
used in a "production" setting.

I think that both languages are perfectly equivalent in this example.

Well, except that the Ruby version is robust against errors and
unexpected inputs, whereas bulletproofing the C version equivalently
would expand it greatly.

-- [mdw]
 
Ad

Advertisements

J

jacob navia

Mark said:
Dereferencing null pointers isn't fun. Let's hope there weren't any
errors setting up that pipe, eh?

It would be highly surprising that in a directory where
there are 600 .c files that doesn't work...

This will incorrectly interpret filenames which contain newline
characters as the names of two or more separate files (which may or may
not exist).

Sure. And I do not care. And if you put 8 backspaces
in a file name it will be kind of invisible duh!
> It will also silently do something wrong on very long file
names (namely to split the file name into 511-byte chunks, with a short
trailing chunk, and treat each chunk as a separate name).

And I do not care either since I know that all file names are
exactly 8 chars long, and with 512 I have enough leeway.

What the regs do not understand is that a script tailored for
a given situation and in a given context is NOT a general
program to compile and run all C files in a given directory.

It is a script for a particular situation in a given software chain.
 
F

Flash Gordon

jacob said:
Flash said:
jacob navia wrote:

#define MAXTESTS 1000
#include <stdio.h>
#include <string.h>

All headers included are above

void ShowFailures(char *tab[],int);
int main(int argc,char *argv[])
{
FILE *f;
char buf[512],cmd[1024], tmpbuf[512];

You might want to use fewer magic numbers and get rid of tmpbuf as you
don't use it.

r = system(cmd);

You might want to include stdlib.h for system.
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
} else {
sprintf(cmd,"gcc %s.o lcclibc_asm.s -lm");

You might want to provide the arguments your format specifier promises.

This is the only error that creeped in when pasting the code and trying
to reformat it.

So the error of failing to include stdlib.h was in your real code? In
that case you should take note of the warnings your compiler does, I'm
sure, produce for it.
should be:


You do not know what C is dude

I know exactly what it is and have done a fair bit of programming in it
for some very different systems.
[snip drivel]

Obviously the regs here do not understand the purpose of scripting.

Wrong, from what I've seen a number of us (including me) do a fir bit of
scripting.
Scripting is a quick program,

Only some times. Some times they are large programs.
not designed for speed or portability

Only some times. Some times they are very much designed for portability
to a specific range of systems.
that fills a task in a production chain.

Definitely only sometimes. There are a *lot* of scripts automating all
sorts of tasks on servers. Others are pushed out to client machines to
automate tasks.
If there are 512 bytes
unused somewhere nobody cares.

You've obviously not done scripting on a system tight on memory (which
is done).

I've written a rather more sophisticatedly build system in DCL in the
past. Entirely non-portable, and targetted at a specific project, bit
very good. Unfortunately I left that company almost 9 years ago so I
don't have it.
By the way, the same code runs under lcc-win under windows.

Wow. It runs on two implementations which are designed to be very similar.
You should
just change the "ls" to "dir /b" and the rest is the same.

So you have to change it.
ANd I will go on posting code here whenever I feel like it.

No where in that post did I complain about you posting code. I just
pointed out a number of errors in your C.
Other people
(like Gordon) can't do that. He has never posted a single line here.

Wrong. I have posted code here on a number of occasions. I don't post
code I write professionally because I don't need help with the C issues
and there are other resources for the non-C issues.

Oh, and it is impolite to use someones last name without the appropriate
honorific, but feel free to use my nick or look up my first name (my
full name is easy to find).
The same for all other "regs" complaining their usual nonsense.

The are unable to do anything constructive and limit themselves to
pissing around other people.

You need to learn that pointing out errors in code is constructive. The
"regs" also post corrected code and alternative versions when they feel
like it.
Well let them do that if they are happy with it.

You have yet to understand what people are doing.
 
B

Ben Bacarisse

George Peter Staplin said:
jacob said:
Common widsom says that python, ruby or similar are good for scripting,
but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.

Setup
----- [snip]

I think that both languages are perfectly equivalent in this example.

The next example I will post is web programming.

Thanks for your attention.

Jacob, there are actually other people that share your view.

The Varnish web cache/accelerator uses VCL as a configuration language, and
then compiles that to C which then is compiled at runtime for use with
Varnish.
<snip other examples of compiling to C>

I think your examples make the opposite point, don't they? Examples of
how people have addressed certain problem areas by using languages
that get turned /into/ C suggests, to me, that these projects decided
(maybe wrongly of course) that C was not suitable for writing the code
in the first place.
 
K

Keith Thompson

jacob navia said:
What the regs do not understand is that a script tailored for
a given situation and in a given context is NOT a general
program to compile and run all C files in a given directory.

It is a script for a particular situation in a given software chain.

We don't understand because you didn't bother to say so.

One advantage of using a scripting language is that a lot of these
details, such as handling arbitrary input lines and file names, is
taken care of automatically; there's no need to assume that input
lines are reasonably sort and file names are sane.

If I were to write an equivalent script in Perl, with a little care,
it would correctly handle things like extremely long file names with
embedded newline characters. Maybe that's not worth worrying about,
but it's worth mentioning.

As you pointed out in your original article, the version written in a
scripting language is of comparable size to the version written in C.
But to get the same safety that the script gives you for free, the C
version would have to be substantially larger.

Is your point that C is a good as a scripting language for a
quick-and-dirty task that's not intended to be portable or reusable?

C is not the best tool for everything. (You'll probably interpret
this as a personal attack on you, the C language, and lcc-win. It
isn't.)

Incidentally, Perl is implemented in C.
 
F

Flash Gordon

jacob said:
Mark Wooding wrote:


Sure. And I do not care. And if you put 8 backspaces
in a file name it will be kind of invisible duh!

Strange things are known to happen.
And I do not care either since I know that all file names are
exactly 8 chars long, and with 512 I have enough leeway.

If you don't tell people what restrictions code is designed to work in
how do you expect them to know?
What the regs do not understand is that a script tailored for
a given situation and in a given context is NOT a general
program to compile and run all C files in a given directory.

Some scripts have very restricted use, others don't.
It is a script for a particular situation in a given software chain.

Only to the same extent that applies to all software.

I have to write scripts which will work much more flexibly and robustly.
If they do something nasty because someone accidentally created a file named
ls ..
cd ..; rm *
then I would be in *serious* trouble. I've not come across that, but I
have seen a file names "*" and files with other commands in the name due
to idiot sysadmins not knowing what they were doing.

Other customers have very good and intelligent sysadmins, and I'm not
going to name either group of customers ;-)
 
Ad

Advertisements

C

CBFalconer

jacob said:
Common widsom says that python, ruby or similar are good for
scripting, but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.
.... snip ...

sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);

I assume you want this to work. It won't. The return value from
'system' does not reflect the success of compilation, although it
may on some systems. The following is an extract from the C
standard.

7.20.4.6 The system function

Synopsis
[#1]
#include <stdlib.h>
int system(const char *string);

.... snip ...

Returns

[#3] If the argument is a null pointer, the system function
returns nonzero only if a command processor is available.
If the argument is not a null pointer, and the system
function does return, it returns an implementation-defined
value. ^^^^^^^^^^^^^^^^^^^^^^

Also consider using my ggets to form buf content in the first
place. That way there is no intrinsic length limitation, and the
final '\n' is automatically removed and zeroed.
 
C

CBFalconer

jacob said:
Keith Thompson wrote:

He wrote that *windows* lcc-win doesn't understand popen...

Obviously I am using Unix lcc-win, that knows about popen
in /usr/include/stdio.h

This would be obvious to anyone but Mr Thompson... Or maybe he
ignores everything about the Unix system, I do not know.

In any case the point of my message is that using C is perfectly
OK as a scripting language and compres equal to ruby.

Mr Thompson did not address those issues.

Here you are starting another pointless fight. You are posting on
c.l.c, where the subject is the C language, as defined by the C
standard. Not some Unix standard. C does not have popen.
 
C

CBFalconer

jacob said:
.... snip ...

By the way, the same code runs under lcc-win under windows. You
should just change the "ls" to "dir /b" and the rest is the same.

ANd I will go on posting code here whenever I feel like it. Other
people (like Gordon) can't do that. He has never posted a single
line here. The same for all other "regs" complaining their usual
nonsense.

I didn't notice any complaints about posting code. I do it all the
time. However I attempt to make that code run on any conformant C
system, and if not there is usually an annotation explaining the
difference.

Notice that I responded to your original post, which did not pick
any fights. You may have noticed that my responses are growing
less sympathetics as I read your attacks on people.
 
Ad

Advertisements

F

Flash Gordon

CBFalconer said:
jacob said:
Common widsom says that python, ruby or similar are good for
scripting, but C is not the right tool for it.

Here is a small "benchmark" that shows that C can be used as a
scripting language in the same way as, for instance, ruby.
.... snip ...
sprintf(cmd,"../lcc -g2 -nw %s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);

I assume you want this to work. It won't. The return value from
'system' does not reflect the success of compilation, although it
may on some systems. The following is an extract from the C

<snip>

That does not mean it will not work. It means it will not work where the
implementation has defined it differently. A very big difference.
 

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

Similar Threads


Top