jwf@munsell.UUCP (Jim Franklin) (02/24/88)
Summary: you can use some simple #define macros to let lint do full type checking on /*VARARGS*/ procedure calls with (keyword, value) parameters. Read on (about 100 lines) for the details ... We have some procedures that take a lot of optional arguments. We clearly want to use varargs.h, and we like the style used by SUN in the various windowing functions, i.e., a zero-terminated list of (keyword, value) pairs. The (keyword, value) pairs improve readability and permit procedure parameters to be specified in any order. For example, #define PIC_COLOR_MODEL_VALUE 1 #define PIC_ADDR_VALUE 2 #define PIC_ACTIVE_IMAGES_VALUE 3 enum color_model_e { color_xyz, color_abc }; #define ACTIVE_X 1 #define ACTIVE_Y 2 #define ACTIVE_Z 4 main () { char *pic_addr = NULL; alloc_picture (PIC_COLOR_MODEL_VALUE, color_xyz, PIC_ADDR_VALUE, pic_addr, PIC_ACTIVE_IMAGES_VALUE, ACTIVE_X + ACTIVE_Y, 0); } The problem with this is that because alloc_picture() must be declared /*VARARGS*/, you lose all type checking from lint. This makes errors in the calling parameters very difficult to find. However, with some #define trickery, I found that you can have varargs and keyword parameters and type checking, with no runtime penalty. You need one #define macro for each (keyword, value) pair, and a collection of functions of the form <type> <type>_arg (x) <type> x; { return (x); } where <type> is the data type of your parameters (int, char *, etc.). For the example above, you define #ifndef lint #define PIC_COLOR_MODEL(x) PIC_COLOR_MODEL_VALUE, (x) #define PIC_ADDR(x) PIC_ADDR_VALUE, (x) #define PIC_ACTIVE_IMAGES(x) PIC_ACTIVE_IMAGES_VALUE, (x) #else #define PIC_COLOR_MODEL(x) \ PIC_COLOR_MODEL_VALUE, color_model_e_arg(x) #define PIC_ADDR(x) PIC_ADDR_VALUE, char_p_arg(x) #define PIC_ACTIVE_IMAGES(x) PIC_ACTIVE_IMAGES_VALUE, int_arg(x) enum color_model_e color_model_e_arg (x) enum color_model_e x; { return (x); } int int_arg (x) int x; { return (x); } char * char_p_arg (x) char *x; { return (x); } #endif main () { char *pic_addr = NULL; alloc_picture (PIC_COLOR_MODEL (color_xyz), PIC_ADDR (pic_addr), PIC_ACTIVE_IMAGES (ACTIVE_X + ACTIVE_Y), 0); } If lint is undefined (i.e., you are just compiling) then the call to alloc_picture() expands to alloc_picture ( 1, (color_xyz), 2, (pic_addr), 3, ( 1 + 2), 0); If lint is defined, it expands to ... all the <type>_arg() functions (deleted for brevity) alloc_picture ( 1, color_model_e_arg(color_xyz), 2, char_p_arg(pic_addr), 3, int_arg( 1 + 2), 0); Lint can now do full type checking on alloc_picture's variable argument list. This is nice ... ----- {harvard!adelie,{decvax,allegra,talcott}!encore}!munsell!jwf Jim Franklin, Eikonix/EPPS, 23 Crosby Drive, Bedford, MA 01730 Phone: (617) 663-2115 x4015