Next: Writing Lisp Primitives, Previous: A Readers Guide to SXEmacs Coding Conventions, Up: Rules When Writing New C Code [Contents][Index]
See (sppm)Coding Style, is a good preamble for this section.
Every module includes <config.h> (angle brackets so that ‘--srcdir’ works correctly; config.h may or may not be in the same directory as the C sources) and lisp.h. config.h must always be included before any other header files (including system header files) to ensure that certain tricks played by various s/ and m/ files work out correctly.
When including header files, always use angle brackets, not double quotes, except when the file to be included is always in the same directory as the including file. If either file is a generated file, then that is not likely to be the case. In order to understand why we have this rule, imagine what happens when you do a build in the source directory using ‘./configure’ and another build in another directory using ‘../work/configure’. There will be two different config.h files. Which one will be used if you ‘#include "config.h"’?
Almost every module contains a syms_of_*()
function and a
vars_of_*()
function. The former declares any Lisp primitives
you have defined and defines any symbols you will be using. The latter
declares any global Lisp variables you have added and initializes global
C variables in the module. Important: There are stringent
requirements on exactly what can go into these functions. See the
comment in emacs.c. The reason for this is to avoid obscure
unwanted interactions during initialization. If you don’t follow these
rules, you’ll be sorry! If you want to do anything that isn’t allowed,
create a complex_vars_of_*()
function for it. Doing this is
tricky, though: you have to make sure your function is called at the
right time so that all the initialization dependencies work out.
Declare each function of these kinds in symsinit.h. Make sure it’s called in the appropriate place in emacs.c. You never need to include symsinit.h directly, because it is included by lisp.h.
All global and static variables that are to be modifiable must
be declared uninitialized. This means that you may not use the
“declare with initializer” form for these variables, such as int
some_variable = 0;
. The reason for this has to do with some kludges
done during the dumping process: If possible, the initialized data
segment is re-mapped so that it becomes part of the (unmodifiable) code
segment in the dumped executable. This allows this memory to be shared
among multiple running SXEmacs processes. SXEmacs is careful to place as
much constant data as possible into initialized variables during the
temacs phase.
Please note: This kludge only works on a few systems nowadays, and is rapidly becoming irrelevant because most modern operating systems provide copy-on-write semantics. All data is initially shared between processes, and a private copy is automatically made (on a page-by-page basis) when a process first attempts to write to a page of memory.
Formerly, there was a requirement that static variables not be declared
inside of functions. This had to do with another hack along the same
vein as what was just described: old USG systems put statically-declared
variables in the initialized data space, so those header files had a
#define static
declaration. (That way, the data-segment remapping
described above could still work.) This fails badly on static variables
inside of functions, which suddenly become automatic variables;
therefore, you weren’t supposed to have any of them. This awful kludge
has been removed in SXEmacs because
The C source code makes heavy use of C preprocessor macros. One popular macro style is:
#define FOO(var, value) do { \ Lisp_Object FOO_value = (value); \ ... /* compute using FOO_value */ \ (var) = bar; \ } while (0)
The do {...} while (0)
is a standard trick to allow FOO to have
statement semantics, so that it can safely be used within an if
statement in C, for example. Multiple evaluation is prevented by
copying a supplied argument into a local variable, so that
FOO(var,fun(1))
only calls fun
once.
Lisp lists are popular data structures in the C code as well as in
Elisp. There are two sets of macros that iterate over lists.
EXTERNAL_LIST_LOOP_n
should be used when the list has been
supplied by the user, and cannot be trusted to be acyclic and
nil
-terminated. A malformed-list
or circular-list
error
will be generated if the list being iterated over is not entirely
kosher. LIST_LOOP_n
, on the other hand, is faster and less
safe, and can be used only on trusted lists.
Related macros are GET_EXTERNAL_LIST_LENGTH
and
GET_LIST_LENGTH
, which calculate the length of a list, and in the
case of GET_EXTERNAL_LIST_LENGTH
, validating the properness of
the list. The macros EXTERNAL_LIST_LOOP_DELETE_IF
and
LIST_LOOP_DELETE_IF
delete elements from a lisp list satisfying some
predicate.
Next: Writing Lisp Primitives, Previous: A Readers Guide to SXEmacs Coding Conventions, Up: Rules When Writing New C Code [Contents][Index]