Go to the first, previous, next, last section, table of contents.
Writing a good library interface takes a lot of practice and thorough understanding of the problem that the library is intended to solve.
If you design a good interface, it won't have to change often, you won't have to keep updating documentation, and users won't have to keep relearning how to use the library.
Here is a brief list of tips for library interface design, which may help you in your exploits:
static
keyword (or equivalent) whenever possible
Writing portable C header files can be difficult, since they may be read by different types of compilers:
extern "C"
directive, so that the
names aren't mangled. See section Writing libraries for C++, for other issues relevant
to using C++ with libtool.
#include
d.
These complications mean that your library interface headers must use some C preprocessor magic in order to be usable by each of the above compilers.
`foo.h' in the `demo' subdirectory of the libtool distribution serves as an example for how to write a header file that can be safely installed in a system directory.
Here are the relevant portions of that file:
/* BEGIN_C_DECLS should be used at the beginning of your declarations, so that C++ compilers don't mangle their names. Use END_C_DECLS at the end of C declarations. */ #undef BEGIN_C_DECLS #undef END_C_DECLS #ifdef __cplusplus # define BEGIN_C_DECLS extern "C" { # define END_C_DECLS } #else # define BEGIN_C_DECLS /* empty */ # define END_C_DECLS /* empty */ #endif /* PARAMS is a macro used to wrap function prototypes, so that compilers that don't understand ANSI C prototypes still work, and ANSI C compilers can issue warnings about type mismatches. */ #undef PARAMS #if defined (__STDC__) || defined (_AIX) \ || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ || defined(WIN32) || defined(__cplusplus) # define PARAMS(protos) protos #else # define PARAMS(protos) () #endif
These macros are used in `foo.h' as follows:
#ifndef FOO_H #define FOO_H 1 /* The above macro definitions. */ #include "..." BEGIN_C_DECLS int foo PARAMS((void)); int hello PARAMS((void)); END_C_DECLS #endif /* !FOO_H */
Note that the `#ifndef FOO_H' prevents the body of `foo.h' from being read more than once in a given compilation.
Also the only thing that must go outside the
BEGIN_C_DECLS
/END_C_DECLS
pair are #include
lines.
Strictly speaking it is only C symbol names that need to be protected,
but your header files will be more maintainable if you have a single
pair of of these macros around the majority of the header contents.
You should use these definitions of PARAMS
, BEGIN_C_DECLS
,
and END_C_DECLS
into your own headers. Then, you may use them to
create header files that are valid for C++, ANSI, and non-ANSI
compilers(6).
Do not be naive about writing portable code. Following the tips given above will help you miss the most obvious problems, but there are definitely other subtle portability issues. You may need to cope with some of the following issues:
void *
generic
pointer type, and so need to use char *
in its place.
const
, inline
and signed
keywords are not
supported by some compilers, especially pre-ANSI compilers.
long double
type is not supported by many compilers.
Go to the first, previous, next, last section, table of contents.