| GNOME Programming Guidelines | |||
|---|---|---|---|
| <<< Previous | Home | Next >>> | |
'Coding style' refers to the way source code is formatted. For C, this involves things like brace placement, indentation, and the way parentheses are used. GNOME has a mix of coding styles, and we do not enforce any one of them. The most important thing is for the code to be consistent within a program or library - code with sloppy formatting is not acceptable, since it is hard to read.
When writing a new program or library, please follow a consistent style of brace placement and indentation. If you do not have any personal preference for a style, we recommend the Linux kernel coding style, or the GNU coding style.
Read the (Standards)Writing C info node in the GNU documentation. Then, get the Linux kernel sources and read the file linux/Documentation/CodingStyle, and ignore Linus's jokes. These two documents will give you a good idea of what we recommend for GNOME code.
For core GNOME code we prefer the Linux kernel indentation style. Use 8-space tabs for indentation.
Using 8-space tabs for indentation provides a number of benefits. It makes the code easier to read, since the indentation is clearly marked. It also helps you keep your code honest by forcing you to split functions into more modular and well-defined chunks - if your indentation goes too far to the right, then it means your function is designed badly and you should split it to make it more modular or re-think it.
8-space tabs for indentation also helps you to design functions that fit nicely in a single screen, which means that people can understand the code without having to scroll back and forth in order to understand it.
If you use Emacs, then you can select the Linux kernel indentation style by including this in your .emacs file:
(add-hook 'c-mode-common-hook
(lambda ()
(c-set-style "k&r")
(setq c-basic-offset 8)))
|
On newer Emacsen or with a newer cc-mode, you may be able to simply do this instead:
(add-hook 'c-mode-common-hook
(lambda ()
(c-set-style "linux")))
|
If you use vim, then you can select the GNOME kernel indentation style by including this fragment in your ~/.vimrc file:
set ts=8
if !exists("autocommands_loaded")
let autocommands_loaded = 1
augroup C
autocmd BufRead *.c set cindent
augroup END
endif
|
The GNU indentation style is the default for Emacs, so you do not need to put anything in your .emacs to enable it. If you wish to select it explicitly, substitute "gnu" for "linux" in the example above.
If you know how to customize indentation styles in other popular editors, please tell us about it so that we can expand this document.
It is important to follow a good naming convention for the symbols in your programs. This is especially important for libraries, since they should not pollute the global namespace - it is very annoying when a library has sloppily-named symbols that clash with names you may want to use in your programs.
Function names should be of the form module_submodule_operation, for example, gnome_canvas_set_scroll_region or gnome_mime_get_keys. This naming convention eliminates inter-module clashes of symbol names. This is very important for libraries.
Symbols should have descriptive names. As Linus says, do not use cntusr(), use count_active_users() instead. This makes code very easy to read and almost self-documenting.
Try to use the same naming conventions as in GTK+ and the GNOME libraries:
Function names are lowercase, with underscores to separate words, like this: gnome_canvas_set_scroll_region(), gnome_mime_get_keys().
Macros and enumerations are uppercase, with underscores to separate words, like this: GNOMEUIINFO_SUBTREE() for a macro, and GNOME_INTERACT_NONE for an enumeration value.
Types and structure names are mixed upper and lowercase, like this: GnomeCanvasItem, GnomeIconList.
Using underscores to separate words makes the code less cramped and easier to edit, since you can use your editor's word commands to navigate quickly.
If you are writing a library, then you may need to have exported symbols that are to be used only within the library. For example, two of the object files that compose the library libfoo.so may need to access symbols from each other, but this symbols are not meant to be used from user programs. In that case, put an underscore before the function name and make the first words follow the standard module/submodule convention. For example, you could have a function called _foo_internal_frobnicate().
It is important that your variables be consistently named. For example, a module that does a list manipulation may choose to name the variables that hold a list pointer "l", for terseness and simplicity. However, it is important that a module that manipulates widgets and sizes does not use variables called "w" for both widgets and widths (as in width/height values); this would make the code inconsistent and harder to read.
Of course, these very short and terse names should only be used for the local variables of functions. Never call a global variable "x"; use a longer name that tells what it does.
GNOME code should be as clean as possible. This implies using a consistent indentation style and good naming conventions, as described above. It also implies the following.
Learn the correct use of the static keyword. Do not make all your symbols global. This has the advantage that you can use shorter names for internal functions within a single source file, since they are not globally visible and thus you do not need the module/submodule prefix.
Learn the correct use of the const keyword. Use it consistently, as it can make the compiler catch a lot of stupid bugs for you.
If you have a function that returns a pointer to internal data which the user is not supposed to free, you should use a const modifier. This will warn the user if he tries to do something incorrect, for example:
const char *gnome_mime_get_info (const char *info); |
The compiler will warn the user if he tries to free the returned string. This can catch a lot of bugs.
If you have random 'magic values' in your program or library, use macros to define them instead of hardcoding them where they are used:
/* Amount of padding for GUI elements */ #define GNOME_PAD 8 #define GNOME_PAD_SMALL 4 #define GNOME_PAD_BIG 12 |
If you have a list of possible values for a variable, do not use macros for them; use an enum instead and give it a type name - this lets you have symbolic names for those values in a debugger. Also, do not use an 'int' to store an enumeration value; use the enum type instead. This lets the compiler catch errors for you, allows the debugger to show proper values for these values and makes it obvious what values a variable can take. An example follows:
/* Shadow types */
typedef enum {
GTK_SHADOW_NONE,
GTK_SHADOW_IN,
GTK_SHADOW_OUT,
GTK_SHADOW_ETCHED_IN,
GTK_SHADOW_ETCHED_OUT
} GtkShadowType;
void gtk_frame_set_shadow_type (GtkFrame *frame, GtkShadowType type);
|
If you define a set of values for a bit field, do it like this:
/* Update flags for items */
enum {
GNOME_CANVAS_UPDATE_REQUESTED = 1 << 0,
GNOME_CANVAS_UPDATE_AFFINE = 1 << 1,
GNOME_CANVAS_UPDATE_CLIP = 1 << 2,
GNOME_CANVAS_UPDATE_VISIBILITY = 1 << 3,
GNOME_CANVAS_UPDATE_IS_VISIBLE = 1 << 4
};
|
This makes it easier to modify the list of values, and is less error-prone than specifying the values by hand. It also lets you use those values as symbols in a debugger.
Do not write obfuscated code, but also try to be spartan. Do not use more parentheses than are necessary to clarify an expression. Use spaces before parentheses and after commas, and also around binary operators.
Please do not put hacks in the code. Instead of writing an ugly hack, re-work the code so that it is clean, extensible and maintainable.
Make sure your code compiles with absolutely no warnings from the compiler. These help you catch stupid bugs. Use function prototypes in header files consistently.
Within GNOME you can use the GNOME_COMPILE_WARNINGS Autoconf macro in your configure.in. This will take care of turning on a good set of compiler warnings in a portable fashion.
Comment your code. Please put a comment before each function that says what it does. Do not say how it does it unless it is absolutely necessary; this should be obvious from reading the code. If it is not, you may want to rework it until the code is easy to understand.
While documenting API functions for a library, please follow the guidelines specified in the file gnome-libs/devel-docs/api-comment-style.txt. This allows your source code to provide inline documentation that is later extracted by the gtk-doc system to create a DocBook manual automatically.
GTK+ lets you do a lot of magic and obfuscation with signal handlers, passed closures, and datasets. If you find yourself doing a lot of gtk_object_set_data() all over the place, or passing state around in bizarre ways via signal handlers, please rework the code. If you need to attach a lot of data to a particular object, then it is a good candidate for a new derived class, which will not only make the code cleaner, but more extensible as well.
A lot of heuristics in complicated event handlers can often be replaced by clean code in the form of a state machine. This is useful when you want to implement tricky things like selection and dragging behavior, and will make the code easier to debug and extend.
| <<< Previous | Home | Next >>> | |
| The Importance of Writing Good Code | Correctness and Robustness | ||