rfarris@rfengr.com (Rick Farris) (02/26/91)
I have a problem that I'm sure has been solved in the C language before; would someone point me in the right direction? I have an enumerated type: typedef enum { A, B, C, D } CMD; and a corresponding array of ascii representations : char ltrs[] = { 'A', 'B', 'C', 'D' }; used for printing and other various purposes. (Of course the real problem is much more complicated than this, but this simple example is sufficient for illustrative purposes.) My problem is: How do I keep the darn things in sync? Suppose I add a new CMD, "Z", is there any way to ensure that ltrs[] is updated? The problem is exacerbated by the fact that the CMD enum, being a typedef, is in a header file that is included in many places. Since ltrs[] is an instantiated variable, it *can't* live in the same place. Where should it live? Thanks! -- Rick Farris RF Engineering POB M Del Mar, CA 92014 voice (619) 259-6793 rfarris@rfengr.com ...!ucsd!serene!rfarris serenity bbs 259-7757
pkr@media01.UUCP (Peter Kriens) (02/27/91)
> typedef enum { A, B, C, D } CMD; > and a corresponding array of ascii representations : > char ltrs[] = { 'A', 'B', 'C', 'D' }; ... > The problem is exacerbated by the fact that the CMD enum, > being a typedef, is in a header file that is included in > many places. Since ltrs[] is an instantiated variable, it > *can't* live in the same place. Where should it live? You could place the table in the header file like typedef enum { A, B, C, D ) CMD; #ifdef _CMDDEF_ char ltrs = { 'A', 'B', 'C', 'D' }; #endif This would at least take care of the fact that they are close together which means that the change of noth being updated simulteneous is actually not zero. The only thing you have to do in the source that is allowed to define the table ltrs, is defining _CMDDEF_ before you include the header file Peter Kriens
peter@ficc.ferranti.com (Peter da Silva) (02/27/91)
In article <1991Feb26.045242.23453@rfengr.com> rfarris@rfengr.com (Rick Farris) writes: > My problem is: How do I keep the darn things in sync? Try this: ---- ltrs.h typedef enum { A, B, C, D } CMD; #ifdef LTRS_C char ltrs[] = { 'A', 'B', 'C', 'D' }; #else extern char ltrs[]; #endif ---- ltrs.c #define LTRS_C #include "ltrs.h" -- Peter da Silva. `-_-' peter@ferranti.com +1 713 274 5180. 'U` "Have you hugged your wolf today?"
jls@yoda.Rational.COM (Jim Showalter) (02/27/91)
In Ada, you'd just use the 'IMAGE attribute on the enumerated type, which would eliminate the double-entry bookkeeping problem you describe at no cost to you. Of course, Ada is a big language with lots of useless bells and whistles, according to every C hacker I've ever met. (No smiley.) -- ***** DISCLAIMER: The opinions expressed herein are my own. Duh. Like you'd ever be able to find a company (or, for that matter, very many people) with opinions like mine. -- "When I want your opinion, I'll beat it out of you."
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (02/27/91)
In article <1991Feb26.045242.23453@rfengr.com>, rfarris@rfengr.com (Rick Farris) writes: > I have a problem that I'm sure has been solved in the C > language before; would someone point me in the right > direction? > typedef enum { A, B, C, D } CMD; > char ltrs[] = { 'A', 'B', 'C', 'D' }; > My problem is: How do I keep the darn things in sync? I've seen this one often enough that I think it belongs in the FAQ list. The answer is that you *don't* do it by any special magic in the C source code itself, but use some other tool to transform a "mini language" to both files. For example, write a little file like cmd.defs ----------- A "Alfa" B "Bravo" ... D "Delta" and two awk scripts: cmd.awk ------------- BEGIN { print "typedef enum {" } { print $1, "," } END { print "} CMD;" } and ltrs.awk ------------- BEGIN { print "char ltrs[] = {" } { print " '" substr($2,1,1) "'," } END { print "};"} and then put in your Makefile cmd.h: cmd.defs cmd.awk awk -f cmd.awk <cmd.defs >cmd.h ltrs.c: cmd.defs ltrs.awk awk -f ltrs.awk <cmd.defs >ltrs.c (This is not a UNIX-specific solution: make and awk lookalikes are available for other systems. If you haven't got them, it's trivial to do this in C itself.) Moral: C source code is plain text that can be generated by other programs. -- The purpose of advertising is to destroy the freedom of the market.
rjohnson@shell.com (Roy Johnson) (02/27/91)
In article <jls.667625530@yoda> jls@yoda.Rational.COM (Jim Showalter) writes: >In Ada, you'd just use the 'IMAGE attribute on the enumerated type, >which would eliminate the double-entry bookkeeping problem you >describe at no cost to you. >Of course, Ada is a big language with lots of useless bells and >whistles, according to every C hacker I've ever met. >(No smiley.) Looks like we need a new newsgroup comp.religion.ada or some such, for people to grouse about how Ada is really better than C, but no one will admit it. Get a life. Sorry for wasting bandwidth...I hope this will prevent more of the same. -- ======= !{sun,psuvax1,bcm,rice,decwrl,cs.utexas.edu}!shell!rjohnson ======= Feel free to correct me, but don't preface your correction with "BZZT!" Roy Johnson, Shell Development Company
lfd@cbnewsm.att.com (Lee Derbenwick) (02/28/91)
In article <1991Feb26.045242.23453@rfengr.com>, rfarris@rfengr.com (Rick Farris) writes: > I have an enumerated type: > > typedef enum { A, B, C, D } CMD; > > and a corresponding array of ascii representations : > > char ltrs[] = { 'A', 'B', 'C', 'D' }; > > My problem is: How do I keep the darn things in sync? This is a bit kludgy, and it doesn't _guarantee_ that they're in sync (i.e., no protection from typos), but its flexible and general, and _very_ easy to do. The key is an include file using macros that are defined differently in different contexts. letters.h contains: LETTER(A, 'A') LETTER(B, 'B') LETTER(C, 'C') LETTER(D, 'D') #undef LETTER Then, to get your two examples: #define LETTER(A,B) A typedef enum { #include "letters.h" } CMD; #define LETTER(A,B) B char ltrs[] = { #include "letters.h" }; This trick can also be useful for creating a number of tables that are really views of a single relation. -- Speaking strictly for myself, -- Lee Derbenwick, AT&T Bell Laboratories, Warren, NJ -- lfd@cbnewsm.ATT.COM or <wherever>!att!cbnewsm!lfd
lfd@cbnewsm.att.com (Lee Derbenwick) (02/28/91)
In article <1991Feb27.182525.29758@cbnewsm.att.com>, I gave a trick for keeping stuff in sync; but I left commas out of the two macro definitions (SORRY ABOUT THAT!): > > letters.h contains: > > LETTER(A, 'A') > LETTER(B, 'B') > LETTER(C, 'C') > LETTER(D, 'D') > #undef LETTER > > Then, to get your two examples: > /* > #define LETTER(A,B) A */ #define LETTER(A,B) A, /* should have been */ > typedef enum { > #include "letters.h" > } CMD; > /* > #define LETTER(A,B) B */ #define LETTER(A,B) B, /* should have been */ > char ltrs[] = { > #include "letters.h" > }; This trick relies on C allowing a trailing comma in an enum or initializer list; this and other machine-generated C code were the reasons that the trailing comma _is_ allowed. -- Speaking strictly for myself, -- Lee Derbenwick, AT&T Bell Laboratories, Warren, NJ -- lfd@cbnewsm.ATT.COM or <wherever>!att!cbnewsm!lfd
harrison@necssd.NEC.COM (Mark Harrison) (02/28/91)
In article <1991Feb26.045242.23453@rfengr.com>, rfarris@rfengr.com (Rick Farris) writes: > I have an enumerated type: > typedef enum { A, B, C, D } CMD; > > and a corresponding array of ascii representations : > char ltrs[] = { 'A', 'B', 'C', 'D' }; > > My problem is: How do I keep the darn things in sync? One way: Have a definition file that builds a header file with the typedef and a C file with the array. I have used this method successfully for things like symbol table string constants and error messages. Example: file foo.def ------------ CMD: A B C D TOKENS: Q X Y generates foo.h: ---------------- typedef enum { A, B, C, D } CMD; typedef enum { Q, X, Y } TOKENS; and foo.c: ---------- char CMD_ltrs[] = { 'A', 'B', 'C', 'D' }; char TOKENS_ltrs[] = { 'Q', 'X', 'Y' }; Awk and Perl are good languages for building tools like this. -- Mark Harrison harrison@necssd.NEC.COM (214)518-5050 {necntc, cs.utexas.edu}!necssd!harrison standard disclaimers apply...
black@blake.u.washington.edu (Jim Black) (02/28/91)
Rick Farris writes : >I have an enumerated type: > >typedef enum { A, B, C, D } CMD; > >and a corresponding array of ascii representations : > >char ltrs[] = { 'A', 'B', 'C', 'D' }; > > [...] > >My problem is: How do I keep the darn things in sync? > >Suppose I add a new CMD, "Z", is there any way to ensure >that ltrs[] is updated? > >The problem is exacerbated by the fact that the CMD enum, >being a typedef, is in a header file that is included in >many places. Since ltrs[] is an instantiated variable, it >*can't* live in the same place. Where should it live? > One was is to use the C preprocessor, as follows: 1. Use a macro in an include file that groups all the related items together. Eg, in "CmdStuff.h": /* CMD ltr etc */ CmdStuff (A, 'A', ..) CmdStuff (B, 'B', ..) CmdStuff (C, 'C', ..) CmdStuff (D, 'D', ..) CmdStuff (Z, 'Z', ..) 2. Then in each source file (or header, as appropriate), define the CmdStuff macro to do what you want in the particular case, and #include "CmdStuff.h" locally. The CMD enum definition would look like this: #define CmdStuff(enumval, ltr, ..) enumval, typedef enum { #include "CmdStuff.h" /* enum values get enumerated here */ } CMD; #undef CmdStuff And the ltrs[] definition would look like this: #define CmdStuff(enumval, ltr, ..) ltr, char ltrs[] = { #include "CmdStuff.h" /* corresponding letter codes get enumerated here */ }; #undef CmdStuff That's the basic idea, you can do more with this than these examples show. Everything is declared together in one place ("CmdStuff.h", here): each time you add a CmdStuff() entry you will be forced to declare all appropriate parallel values, as intended. P.S. I can't remember if some C compilers might complain about a trailing comma in the aggregate initialization (mine doesn't) - but you can add a trailing null/nil/bottom entry in such cases. Often that's useful anyway. -- Jim Black (black@blake.u.washington.edu)
lerman@stpstn.UUCP (Ken Lerman) (02/28/91)
In article <1991Feb26.045242.23453@rfengr.com> rfarris@rfengr.com (Rick Farris) writes: ............ >I have an enumerated type: > >typedef enum { A, B, C, D } CMD; > >and a corresponding array of ascii representations : > >char ltrs[] = { 'A', 'B', 'C', 'D' }; > >used for printing and other various purposes. ............. >My problem is: How do I keep the darn things in sync? > >Suppose I add a new CMD, "Z", is there any way to ensure >that ltrs[] is updated? >The problem is exacerbated by the fact that the CMD enum, >being a typedef, is in a header file that is included in >many places. Since ltrs[] is an instantiated variable, it >*can't* live in the same place. Where should it live? .................. >-- >Rick Farris RF Engineering POB M Del Mar, CA 92014 voice (619) 259-6793 >rfarris@rfengr.com ...!ucsd!serene!rfarris serenity bbs 259-7757 I saw this idea in the gnu C compiler. In file defs.h: /* establish the pairs */ xxx(A,'A'), xxx(B,'B'), xxx(C,'C'), xxx(D,'D'), Then in file use1.c: #define xxx(a,b) a typedef enum { #include "defs.h" } CMD; #undef xxx In file use2.c (or in another place in the same file): #define xxx(a,b) b char ltrs[] = { #include "defs.h" }; #undef xxx I haven't actually tried this, or there may be some typos, but I think the idea is worth posting. Ken
rlk@telesoft.com (Bob Kitzberger @sation) (02/28/91)
Rick Farris writes: > typedef enum { A, B, C, D } CMD; > > and a corresponding array of ascii representations : > > char ltrs[] = { 'A', 'B', 'C', 'D' }; Yes, you asked for a C solution, but since this was cross-posted to comp.software-eng I thought I'd point out Ada's solution to this. The example below specifies a type 'color', and a call to a language-defined attribute of this prefix, 'IMAGE. with text_io; procedure foo is type color is (red, green, blue ); my_color : color := green; begin text_io.put_line( color'image(my_color) ); end foo; All enumerated types have a corresponding 'IMAGE attribute, which implies that an ASCII (or EBCDIC ;-) representation of each enumerated value be present at execution time. These image tables may be supressed at compile time. .Bob. -- Bob Kitzberger Internet : rlk@telesoft.com TeleSoft uucp : ...!ucsd.ucsd.edu!telesoft!rlk 5959 Cornerstone Court West, San Diego, CA 92121-9891 (619) 457-2700 x163 ------------------------------------------------------------------------------ "Wretches, utter wretches, keep your hands from beans!" -- Empedocles
dave@aspect.UUCP (Dave Corcoran) (03/01/91)
In article <1991Feb26.045242.23453@rfengr.com>, rfarris@rfengr.com (Rick Farris) writes: > I have an enumerated type: > > typedef enum { A, B, C, D } CMD; > > and a corresponding array of ascii representations : > > char ltrs[] = { 'A', 'B', 'C', 'D' }; > > Suppose I add a new CMD, "Z", is there any way to ensure > that ltrs[] is updated? > run this through m4 you might be pleasantly suprised; although anyone maintaining your code may what to drop the adjective "pleasantly" :-) define(awkdef, `syscmd((echo ' '$2' | sed 's/^(//;s/^)//' `>/tmp/am_$1))' `define($1,`syscmd(awk $'`2 -f /tmp/am_$1 ifelse($'`1,,,<<@@ $'`1 @@))')' ) awkdef(xx,( # note the leading ( BEGIN {printf "enum {"} { for (i=1;i<=NF;i++) printf "%s,",$i } END {print "} CMD;"} )) /* note the first paren MUST be flush against the left margin */ /* note the '\'' construct is needed to get a single ' in the output */ awkdef(yy,( BEGIN {printf "char ltrs[] = {"} { for (i=1;i<=NF;i++) printf "'\''%s'\'',",$i } END {print "};"} )) define(letters,`xx($1)yy($1)') letters(A B C D E F G H I J K L M) /* if you need conditional compliation */ define(`letters',`ifdef(`header_file',`yy($1)',`xx($1)')') /* this next line would be in a .c source */ letters(A B C) /* these two would be in a .h header */ define(header_file) letters(A B C) -- David Corcoran -@@ uunet!aspect!dave ~ In a society where anything goes eventually everything will.
jih@ox.com (John Hritz) (03/02/91)
The approach I take when faced with this kind of problem is to place an assert statement in the main() as a check. assert(sizeof(a) == sizeof(b)) will probably do the trick. These statements can be left out of the code by setting a compile switch, usually NDEBUG. -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= John I. Hritz Photons have mass?! jih@ox.com I didn't know they 313-930-9126 were catholic!
rjc@uk.ac.ed.cstr (Richard Caley) (03/02/91)
In article <1991Feb26.045242.23453@rfengr.com>, Rick Farris (rf) writes: rf> My problem is: How do I keep the darn things in sync? I had to do this for six or seven sets of things in a library. I decided to write a short shell script to write all the code for me. I created a file containing the names and any data to be associated with them and the shell script creats a header and a c file a file called people with... char *name int age fred fred 24 mary mary 30 would give a header person.h containing enum person { pe_NIL= -1, pe_fred=0, pe_mary=1, pe_number=2, }; struct person_rec { char *name; int age; }; struct person_rec person_data; enum person person_with_name(char *name); enum person person_with_age(int age); and a c file person.c contining the definition of person_data and the code for the search routines (left as an exercise for the reader). The Makefile takes care of recreating the files when needed and nothing can get out of step. Also saves lots of tedious coding of access routines which are isomorphic for all the tables. (the reson for having a separate "name" field is that often things have names which are not legal c tokens). -- rjc@cstr.ed.ac.uk
rlk@telesoft.com (Bob Kitzberger @sation) (03/03/91)
Folks, the intent was to ease an existing maintenance problem. Adding preprocessors such as awk or m4 into the loop only trades one maintenance problem for another. .Bob. -- Bob Kitzberger Internet : rlk@telesoft.com TeleSoft uucp : ...!ucsd.ucsd.edu!telesoft!rlk 5959 Cornerstone Court West, San Diego, CA 92121-9891 (619) 457-2700 x163 ------------------------------------------------------------------------------ "Wretches, utter wretches, keep your hands from beans!" -- Empedocles
harrison@necssd.NEC.COM (Mark Harrison) (03/04/91)
In article <1210@telesoft.com>, rlk@telesoft.com (Bob Kitzberger @sation) writes: > Folks, the intent was to ease an existing maintenance problem. Adding > preprocessors such as awk or m4 into the loop only trades one maintenance > problem for another. That is correct, but the new maintenance problem is easier. Our "bells and whistles" version of the preprocessor ended up being about three pages of AWK that hardly ever needed to be touched. (The only times we did touch it was to make changes in the generated troff documentation to fit our documentation dept's. style). Using MAKE ensured that the preprocessed files stayed in sync. Being able to generate documentation saved us days over the old "red-pencil" method of dealing with our documentation group. -- Mark Harrison harrison@necssd.NEC.COM (214)518-5050 {necntc, cs.utexas.edu}!necssd!harrison standard disclaimers apply...
dave@bigguy.ocpt.ccur.com (David F. Carlson) (03/19/91)
> Rick Farris writes: > > > typedef enum { A, B, C, D } CMD; > > > > and a corresponding array of ascii representations : > > > > char ltrs[] = { 'A', 'B', 'C', 'D' }; > I would usually overload the operation for this using the initialization property of enum types and the fact that they are defined to hold an integer: typedef enum { A = (int) 'A', B = (int) 'B', C = (int) 'C', D = (int) 'D'} CMD; or if lexically ASCII is assumed, typedef enum { A = (int) 'A', B, C, D } CMD; Since B, C and D will be sequential, they will be correctly initialized. Or is that cheating? :-) -- David F. Carlson, Concurrent Computer Co. dave@bigguy.ocpt.ccur.com Fairport, NY "The faster I go, the behinder I get." --Lewis Carroll