Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10 5/3/83; site oliveb.UUCP Path: utzoo!linus!decvax!decwrl!sun!qubix!ios!oliveb!jerry From: jerry@oliveb.UUCP (Jerry Aguirre) Newsgroups: net.lang.c Subject: strings in defs.h force recompiles when changed. Message-ID: <206@oliveb.UUCP> Date: Tue, 30-Oct-84 15:06:34 EST Article-I.D.: oliveb.206 Posted: Tue Oct 30 15:06:34 1984 Date-Received: Fri, 2-Nov-84 04:10:43 EST Organization: Olivetti ATC, Cupertino, Ca Lines: 95 It is fairly common practice when writing large programs in C to break them into individually compiled files. To provide for easy maintenance of these files "constants" are declared in a common include file hereafter referred to as "defs.h". The usenet news software is a good example. It's defs.h file contains "constants" such as: #define NEWS_VERSION "B 2.10.2 9/5/84" #define DFLTSUB "general,all.general" #define TMAIL "/usr/ucb/Mail" #define ADMSUB "general,all.announce" #define PAGE "/usr/ucb/more" #define NOTIFY "usenet" #define DFTXMIT "uux - -r -z %s!rnews < %s" #define UXMIT "uux -r -z -c %s!rnews '<' %s" #define DFTEDITOR "vi" One purported reason for localizing these strings into a single place is to make them easy to change. There is one problem with this scheme. Change just one string, that might only be used in one module, and the makefile will force the recompilation of every damn module in the package! This negates most of the advantage of using make(1) as the most commonly modified items force the recompilation of everything. You might as well use a shell script to compile everything as most of the time there will be no selective recompilation. I have been experimenting with an alternate scheme that, while more complex to set up, has several advantages. This scheme splits the information into two files hereafter referred to as "defs.h" and "strings.c". The strings.c file looks like: char *strings[] = { "B 2.10.2 9/5/84", "general,all.general", "/usr/ucb/Mail", "general,all.announce", "/usr/ucb/more", "usenet", "uux - -r -z %s!rnews < %s", "uux -r -z -c %s!rnews '<' %s", "vi" }; And the defs.h file now looks like: extern char *strings[]; #define NEWS_VERSION strings[0] #define DFLTSUB strings[1] #define TMAIL strings[2] #define ADMSUB strings[3] #define PAGE strings[4] #define NOTIFY strings[5] #define DFTXMIT strings[6] #define UXMIT strings[7] #define DFTEDITOR strings[8] The rest of the modules are unchanged in their usage of the defines. The makefile includes a new module strings.o. It is just as easy to edit strings.c as defs.h so modification is no harder. The advantages are: 1 - Changes do not force recompiling every module. Change the default news group and only strings.c gets recompiled. 2 - Promotes the use of a single copy of each string. If you have five places in the program where it does a: strcpy(buf, DFLTSUB); you still only use one string. The old defs.h would result in five copies of the string. The only deficiencies that I can see are: 1 - The strings involved must be "read only" as there is only a single copy of them. This is usually the case and results in advantage 2 above. 2 - The defs.h and strings.c files must track each other. New strings can be easily added to the end but if a string is removed the offsets in the defs.h file must be changed to match. It is probably easier to just use a zero entry in the strings array and keep the numbering the same. If the numbering did get off the results could be pretty bizarre. I usually extend the strings array to include common strings such as: "Can not open \"%s\"", "Can not create \"%s\"", "Can not read from \"%s\"", "Can not write to \"%s\"" A more general solution should probably use this scheme for other constants. One could have a "const.h" file that had strings[], integers[], floats[], etc. The problem is that most integer defines are used at compile time in array size definitions and switch cases. Any opinions on the problem or the solution? Jerry Aguirre {hplabs|fortune|idi|ihnp4|ios|tolerant|allegra|tymix}!oliveb!jerry