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 that may help you in your exploits:
Try to make every interface truly minimal, so that you won’t need to delete entry points very often.
Some people love redesigning and changing entry points just for the heck of it (note: renaming a function is considered changing an entry point). Don’t be one of those people. If you must redesign an interface, then try to leave compatibility functions behind so that users don’t need to rewrite their existing code.
The fewer data type definitions a library user has access to, the better. If possible, design your functions to accept a generic pointer (that you can cast to an internal data type), and provide access functions rather than allowing the library user to directly manipulate the data. That way, you have the freedom to change the data structures without changing the interface.
This is essentially the same thing as using abstract data types and inheritance in an object-oriented system.
If you are careful to document each of your library’s global functions and variables in header files, and include them in your library source files, then the compiler will let you know if you make any interface changes by accident (see Writing C header files).
static
keyword (or equivalent) whenever possible ¶The fewer global functions your library has, the more flexibility you’ll have in changing them. Static functions and variables may change forms as often as you like… your users cannot access them, so they aren’t interface changes.
The number of elements in a global array is part of an interface, even
if the header just declares extern int foo[];
. This is because
on i386 and some other SVR4/ELF systems, when an application
references data in a shared library the size of that data (whatever
its type) is included in the application executable. If you might
want to change the size of an array or string then provide a pointer
not the actual array.