DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Complying with standard C

Example

This example writes an error handler function called errmsg that returns void, and whose only fixed parameter is an int that specifies details about the error message. This parameter may be followed by a file name, or a line number, or both, and these are followed by printf-like format and arguments that specify the text of the error message.

In order to allow this example to compile with earlier compilers, it makes extensive use of the macro __STDC__ which is defined only for ANSI C compilation systems. Thus the function's declaration (in the appropriate header file) would be:

   #ifdef __STDC__
       void errmsg(int code, ...);
   #else
       void errmsg();
   #endif

The file that contains the definition of errmsg is where the old and new styles can get complex. First, the header to include depends on the compilation system:

   #ifdef __STDC__
   #include <stdarg.h>
   #else
   #include <varargs.h>
   #endif
   #include <stdio.h>
(stdio.h is included because it is needed to call fprintf and vfprintf later.)

Next comes the function's definition. The identifiers va_alist and va_dcl are part of the old-style varargs.h interface.

   void
   #ifdef __STDC__
   errmsg(int code, ...)
   #else
   errmsg(va_alist) va_dcl /* note: no semicolon! */
   #endif
   {
       /* more detail below */
   }
Since the old-style variable argument mechanism did not allow specification of any fixed parameters (at least not officially), we need to arrange for them to be accessed before the varying portion. Also due to the lack of a name for the ``...'' part of the parameters, the new va_start macro has a second argument -- the name of the parameter that comes just before the ``...'' terminator.


NOTE: ANSI C, as an extension, allows functions to be declared and defined with no fixed parameters, as in:

int f(...);

For such functions, va_start should be invoked with an empty second argument, as in:

va_start(ap,)


The following is the body of the function:

   {
       va_list ap;
       char *fmt;

#ifdef __STDC__ va_start(ap, code); #else int code;

va_start(ap); /* extract the fixed argument */ code = va_arg(ap, int); #endif if (code & FILENAME) (void)fprintf(stderr, "\"%s\": ", va_arg(ap, char *)); if (code & LINENUMBER) (void)fprintf(stderr, "%d: ", va_arg(ap, int)); if (code & WARNING) (void)fputs("warning: ", stderr); fmt = va_arg(ap, char *); (void)vfprintf(stderr, fmt, ap); va_end(ap); }

Both the va_arg and va_end macros work the same for the old-style and ANSI C versions. Because va_arg changes the value of ap, the call to vfprintf cannot be:
   (void)vfprintf(stderr, va_arg(ap, char *), ap);
The definitions for the macros FILENAME, LINENUMBER, and WARNING are presumably contained in the same header as the declaration of errmsg.

A sample call to errmsg could be:

   errmsg(FILENAME, "<command line>", "cannot open: %s\n",
          argv[optind]);

Next topic: Promotions: unsigned vs. value preserving
Previous topic: Functions with varying arguments

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004