Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!uflorida!uakari.primate.wisc.edu!sdd.hp.com!usc!snorkelwacker!bloom-beacon!daemon From: scs@adam.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Re: Is this bad programming? Summary: table lookup Keywords: #define array definition Message-ID: <1990Aug9.054556.22271@athena.mit.edu> Date: 9 Aug 90 05:45:56 GMT References: <1990Aug8.100614.1223@resam.dk> Sender: daemon@athena.mit.edu (Mr Background) Reply-To: scs@adam.mit.edu (Steve Summit) Organization: Thermal Technologies, Inc. Lines: 71 In article <1990Aug8.100614.1223@resam.dk> andrew@resam.dk (Leif Andrew Rump) worries about keeping error numbers in sync with an array of error message strings so that the array can be indexed by the array number. Whenever I'm serious about making the connection between error numbers and messages explicit rather than implicit, I do so quite, er, explicitly: #define FILE_FOOTER_ERROR 1 #define DRAW_FOOTER_ERROR 2 #define GRAP_FOOTER_ERROR 3 #define BASE_FRAME_CREATE_ERROR 4 struct errmess { int em_number; char *em_text; } errmesses[] = { FILE_FOOTER_ERROR, "File footer error", DRAW_FOOTER_ERROR, "Draw footer error", GRAP_FOOTER_ERROR, "Grap footer error", BASE_FRAME_CREATE_ERROR,"Base_frame creation error", }; This essentially just removes the comment delimiters placed around the implicit subscripts that are usually provided to remind the programmer what is going on (i.e. /*01*/ "File footer error", in Leif's example). This setup still has the disadvantages that the two components of each line of the structure array definition are quite repetetitive (FILE_FOOTER_ERROR vs. "file footer error"), and every new error number must be added in two places (another #define and another row in the table). A special-purpose preprocessor (perhaps a sed or awk script) could easily automate the table building, if appropriate. Of course, once the array of structures is set up, it's a simple matter to write a little routine char *errtext(int errnum) which takes an error number and searches the array, returning (similarly to the standard library routine strerror) the corresponding error string, or "Error %d", (with %d filled in, of course) for the eventual undefined or illegal error. The scheme has a few other advantages: error numbers can start at 0, 1, or any other number, they can be sparse or negative, and the existence (and mandated use; nobody can cheat and index on an array) of the errtext() routine means there's a convenient hook (namely, the errtext routine itself) for changing things later to pull error messages out of a file at run time or some other useful game. Someone will howl that a linear scan of the error number/string pairing array would be "too inefficient," but I would point out that (a) it wouldn't, if there are a reasonable number of error numbers, and (b) error message printing is not usually a bottleneck, and (c) you could rewrite the routine to use binary search (or, God help you, a hash table) if you really wanted to. (That's another nice thing about a functional interface: you can always drop in some other implementation, that needs to gain control to do something, that you wouldn't be able to do if the "interface" were simply the access by the "caller" of a global variable or array.) Steve Summit scs@adam.mit.edu