Grouse: What's the point of enum?

burkhard burow burow at cernvax.cern.ch
Sun Apr 21 18:37:25 AEST 1991


[] On 18 Apr 91 04:26:15 GMT, rogue at cellar.UUCP (Rogue Winter) said:

RW> If the names given to enumerated values cannot be printed, why do
RW> they exist?  The only purpose I can see is that they become local
RW> symbolic constants.

Below, in enum.h, is a souped up 'enum' and an example program follows in
enum.c. Cut 'em out, compile, and a demo's ready for you.

In no more code than a regular typedef enum, the macros ENUMn(...), where n is
the number of constants in the enumeration, provides:
i)   the constants.
ii)  the number of constants.
iii) an array of the constant names as strings.
iv)  a macro to recognize a particular constant in the enumeration.
v)   addition of another constant to the enumeration without changing a single
      line of code elsewhere.

WARNING: In the following, as far as I know, the only deviation from ANSI C is
the '/**/' kludge for the preprocessor concatenation operator '##'. I use ENUMn
on: VAX VMS: C 3.1 and MIPS Computer Systems 2.0 (e.g. SGI and DECstations).
Some 'guidelines' for these two machines are given in enum.h.


May it amuse,
burkhard            burow at vxdesy.cern.ch

------------cut here for enum.c------------------------------------------------
/* enum.c  An example of the macros in enum.h */
/* Burkhard Burow, University of Toronto, 1990. */

#include "enum.h"
#include <stdio.h>

#define MIN(A,B) ((A)<(B)?(A):(B))

/* Note that adding another constant to the following line requires no change
in any other line of code. */
#ifndef mips
ENUM5(LIST, JUST, SOME, SILLY, STUFF, AGAIN);
#else
ENUM5(LIST,JUST,SOME,SILLY,STUFF,AGAIN);
#endif

main ()
{
int i, loop; char s[99]; 
LIST list;

puts("The enum 'LIST' has the following enumerated constants.");
for (i=0; i<(int)LISTS; i++) printf("  %s", enum_str(LIST)[i]);

puts("\n Please enter one of the above constants: ");
gets(s);

for (loop=0; loop<4; loop++) {
  switch (loop) {
  case 0: printf("An exact comparison");
          ENUMno(LIST, s, 9999,                                     i);
          break;
  case 1: printf("A comparison of the first strlen('LIST' element) characters");
          ENUMno(LIST, s, strlen(enum_str(LIST)[i]),                i);
          break;
  case 2: printf("A comparison of the first strlen(%s) characters",s);
          ENUMno(LIST, s, strlen(s),                                i);
          break;
  case 3: printf("A comparison of the first ");
          printf("MIN(strlen(%s), strlen('LIST' element) ) characters", s);
          ENUMno(LIST, s, MIN(strlen(s),strlen(enum_str(LIST)[i])), i);
          break;
  }
  if (i==(int)LISTS) 
    printf("\n does not recognize %s as a constant in 'LIST'\n\n", s);
  else 
    printf("\n recognizes %s as the constant %s in 'LIST'\n\n", s,
           enum_str(LIST)[i]);
}
}

------------cut here for enum.h------------------------------------------------
/* enum.h */
/* Burkhard Burow, University of Toronto, 1990. */

#ifndef __ENUM_LOADED
#define __ENUM_LOADED	1

static char *nonindent(char *s) { while(*s==' ')s++; return s; }


#include <stdio.h>
#include <string.h>

/* Souped up enum => ENUM1->ENUMn. Typedef's NAME as enumerated with the n given
   constants. enum_str(NAME) is an array of the constants as strings and NAMES
   is the number of constants. Macro ENUMno recognizes constant from a string.
VAX WARNING: The arguments to ENUMn should be be immediately followed by the ','
         or ')'. Trailing whitespace characters are part of the argument, and as
         such will be included in the string created for each tag and hence 
         will cause difficulties when ENUMno searching for tags. 
MIPS WARNING: Same as the VAX but space after the comma and before the argument
         is also included in that argument. Therefore to maintain portability
         across VAXen and MIPS', remove all spaces in ENUMi(...) and
         in enum_str(...) calls. Alternatively, to preserve readability, use
         #ifndef mips
           for calls to ENUMi(..) and enum_str(...) with spaces for readability 
            and behind the 
         #else
           have the same calls with all spaces removed. 
N.B. MIPS machines include SGI's and DECstations. */

#define enum_str(NAME) ENUM_/**/NAME
#define ENUMNO(ENUM_NAME, NAMES, STRING, LENGTH, NO)                           \
 for (NO=0; NO<(int)NAMES; NO++)                                               \
   if (strncmp(STRING,ENUM_NAME[NO],LENGTH)==0) break;
#define ENUMno(NAME, STRING, LENGTH, NO)                                       \
 ENUMNO(enum_str(NAME), NAME/**/S, STRING, LENGTH, NO)

/* char *ENUM_NAME[]; int NAMES; char *STRING; int LENGTH; int NO;
  - NO returns enum. tag of ENUM_NAME matching LENGTH characters of STRING.
  - If none of the NAMES tags match STRING, NO returns NAMES.
  - For exact  comparison with STRING      use LENGTH as a_really_big_int.
  - For prefix comparison on   STRING      use LENGTH as strlen(ENUM_NAME[NO]). 
  - For prefix comparison on   ENUM_NAME's use LENGTH as strlen(STRING).      
  - For prefix comparison on   either      use LENGTH as 
                              MIN(strlen(STRING),STRLEN(ENUM_NAME[NO])).      */

#define ENUM1(NAME, A)               typedef enum{A,NAME/**/S}NAME;            \
 static char *enum_str(NAME)[] = {"A"}
#define ENUM2(NAME, A,B)             typedef enum{A,B,NAME/**/S}NAME;          \
 static char *enum_str(NAME)[] = {"A","B"}
#define ENUM3(NAME, A,B,C)           typedef enum{A,B,C,NAME/**/S}NAME;        \
 static char *enum_str(NAME)[] = {"A","B","C"}
#define ENUM4(NAME, A,B,C,D)         typedef enum{A,B,C,D,NAME/**/S}NAME;      \
 static char *enum_str(NAME)[] = {"A","B","C","D"}
#define ENUM5(NAME, A,B,C,D,E)       typedef enum{A,B,C,D,E,NAME/**/S}NAME;    \
 static char *enum_str(NAME)[] = {"A","B","C","D","E"}
#define ENUM6(NAME, A,B,C,D,E,F)     typedef enum{A,B,C,D,E,F,NAME/**/S}NAME;  \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F"}
#define ENUM7(NAME, A,B,C,D,E,F,G)                                             \
 typedef enum{A,B,C,D,E,F,G,NAME/**/S}NAME;                                    \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G"}
#define ENUM8(NAME, A,B,C,D,E,F,G,H)                                           \
 typedef enum{A,B,C,D,E,F,G,H,NAME/**/S}NAME;                                  \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H"}
#define ENUM11(NAME, A,B,C,D,E,F,G,H,I,J,K)                                    \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,NAME/**/S}NAME;                            \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K"}
#define ENUM12(NAME, A,B,C,D,E,F,G,H,I,J,K,L)                                  \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,NAME/**/S}NAME;                          \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                                  "L"}
#define ENUM13(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M)                                \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,NAME/**/S}NAME;                        \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                                  "L","M"}
#define ENUM15(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O)                            \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,NAME/**/S}NAME;                    \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                                  "L","M","N","O"}
#define ENUM16(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)                          \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,NAME/**/S}NAME;                  \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                                  "L","M","N","O","P"}
#define ENUM20(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U)                  \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,NAME/**/S}NAME;          \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                                  "L","M","N","O","P","Q","R","T","U"}
#define ENUM46(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,        \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV)               \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,               \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,NAME/**/S}NAME;\
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                      "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \
  "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK",                      \
  "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV"}
#define ENUM48(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,        \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX)         \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,               \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,         \
 NAME/**/S}NAME;                                                               \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                      "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \
  "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK",                      \
  "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX"}
#define EXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)                              \
 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
#define QEXPAND16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)                             \
 "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"
/* N.B. e.g. ENUM78(NAME, 52 args, (16 args) ) req.d because VAX C limits 
   number of macro args to 64. */
#define ENUM78(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,        \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ,   \
 BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS16)                                   \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,               \
  AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ,  \
  BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND16/**/ARGS16,NAME/**/S}NAME;       \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                      "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \
  "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK",                      \
  "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ",       \
  "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL",                 \
  QEXPAND16/**/ARGS16}
#define EXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)                          \
 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R
#define QEXPAND18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)                         \
 "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R"
/* N.B. ENUM80(NAME, 52 args, (18 args) ) syntax req.d because VAX C limits 
   number of macro args to 64. */
#define ENUM80(NAME, A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,        \
 AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ,   \
 BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,ARGS18)                                   \
 typedef enum{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,T,U,V,W,X,Y,Z,               \
  AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AT,AU,AV,AW,AX,AY,AZ,  \
  BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,EXPAND18/**/ARGS18,NAME/**/S}NAME;       \
 static char *enum_str(NAME)[] = {"A","B","C","D","E","F","G","H","I","J","K", \
                      "L","M","N","O","P","Q","R","T","U","V","W","X","Y","Z", \
  "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK",                      \
  "AL","AM","AN","AO","AP","AQ","AR","AT","AU","AV","AW","AX","AY","AZ",       \
  "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL",                 \
  QEXPAND18/**/ARGS18}


#endif					/* __ENUM_LOADED */



More information about the Comp.lang.c mailing list