Powers of C

Chris Torek chris at umcp-cs.UUCP
Fri Jul 11 06:01:17 AEST 1986


>In article <2306 at umcp-cs.UUCP> I wrote:
>>I have come to favour
>>
>>	if ((prog_name = rindex(*argv, '/')) != NULL)
>>		...

In article <6061 at sri-spam.ARPA> argv at sri-spam.arpa (AAAARRRRGGGGv) replies:
>Why do the above, when in my first example:
>
>if (prog_name = rindex(*argv, '/'))
>
>is all that's needed.

For clarity, readability.  I used to believe as you seem to do---until
I started looking at my own old code after a few years.

>Given that sometimes there may be "tricky" expressions, it is up to the
>programmer to comment code well enough so that quick skims of said code
>won't confuse the reader too much.

Comments and code have a strange tendency to `get out of sync'.

>I strongly believe that code should NOT be made less efficient for
>readability issues.

Surprise!

	if (v = e)

and

	if ((v = e) != 0)

generate the same code (at least via the 4.3BSD Vax C compiler).
	
>Readability can be made acceptable to even novice programmers with
>efficient use of comments and descriptive variable names -- both of
>which have no effect on the speed of code.

Both do indeed help; I am not certain that they are always sufficient.

[and a digression]

>I like to use my own error statements and print statments for better
>control as described below..
>
>/*VARARGS*/
>print(fmt, args)
>register char *fmt;
>char *args;
>{
>    /* other type of actions done here */
>    _doprnt(fmt, &args, stdout);
>    fflush(stdout);
>}
>
>/*VARARGS*/
>error(fmt, args)
>register char *fmt;
>char *args;
>{
>    /* additional actions done here */
>    print(fmt, args);
>    print(": %s\n", sys_errlist[errno]);
>}
>
>as you can see, I'm using "print" like printf, and it works fine.

Wait until you port your code to a Pyramid.

>error() is like "perror" except that it is now (functionally) like
>printf(). The problem is that error can only take one additional
>argument than "fmt" [...]
>
>The reason is that error is receiving the args right, but since
>its address is being passed to print(), only the address of the
>first arg can be seen by print, thus, all the rest of the args
>that _doprnt finally sees are NULL's.

Well, no, actually, _doprnt gets `stack junk'.  With enough format
elements, and a bit of luck, you might reach error's arguments.
(But not likely on a Pyramid!)

>The qustion (at last) is, how can a variable number of args be
>`elegantly' passed to error and then passed to print so that
>the _doprint in print() sees all the arguments.

First, get yourself a vprintf (the one I just posted should do).
Then do this:

	#include <varargs.h>

	extern int errno;
	extern char *sys_errlist[];
	extern int sys_nerr;

	void
	error(va_alist)
		va_dcl	/* note no semicolon */
	{
		register int e = errno;
		char *fmt;
		va_list v;

		va_start(v);
		fmt = va_arg(v, char *);
		(void) vprintf(fmt, v);
		va_end(v);
		if (e < 0 || e >= sys_nerr)
			printf(": unknown error code %d\n", e);
		else
			printf(": %s\n", sys_errlist[e]);
	}

I prefer a routine more like my own error(), which takes the error
number as an argument (sometimes after the error you should clean
up a bit before printing the message, and the cleanup may disturb
errno; it is ugly to have to `put it back'), and an exit code,
which is passed to exit() iff it is nonzero, else error() returns.
Also, error messages should most likely go to stderr.

My real preference would be to have a functional interface, with
sensible defaults, but that is trickier, given stdio's current
internals.

[enter ANSI C mode]

	static void
	putc_stderr(int c) {

		(void) putc(c, stderr);
	}

	void
	errf(void (*put)(), int quit, int err, const char *fmt, int args) {

		if (put == NULL)
			put = putc_stderr;
		if (err < 0)		/* get system error index */
			err = errno;
		/* somehow do the printing */
		if (quit)
			exit(quit);
	}

There are some efficiency issues here too: it might be useful to
buffer the characters being put, and fflush afterward; but there
is no way to tell what to flush.  I suppose the series of functions
errf(), ferrf(), serrf(), verrf(), vferrf(), vserrf() would suffice.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris at umcp-cs		ARPA:	chris at mimsy.umd.edu



More information about the Comp.lang.c mailing list