Coding Style
Bad Identifiers
Identifiers that conflict and should be avoided.
This is the list of names “reserved to the
implementation” that have been claimed by certain
compilers and system headers of interest, and should not be used
in the library. It will grow, of course. We generally are
interested in names that are not all-caps, except for those like
"_T"
For Solaris:
_B
_C
_L
_N
_P
_S
_U
_X
_E1
..
_E24
Irix adds:
_A
_G
MS adds:
_T
__deref
BSD adds:
__used
__unused
__inline
_Complex
__istype
__maskrune
__tolower
__toupper
__wchar_t
__wint_t
_res
_res_ext
__tg_*
VxWorks adds:
_C2
For GCC:
[Note that this list is out of date. It applies to the old
name-mangling; in G++ 3.0 and higher a different name-mangling is
used. In addition, many of the bugs relating to G++ interpreting
these names as operators have been fixed.]
The full set of __* identifiers (combined from gcc/cp/lex.c and
gcc/cplus-dem.c) that are either old or new, but are definitely
recognized by the demangler, is:
__aa
__aad
__ad
__addr
__adv
__aer
__als
__alshift
__amd
__ami
__aml
__amu
__aor
__apl
__array
__ars
__arshift
__as
__bit_and
__bit_ior
__bit_not
__bit_xor
__call
__cl
__cm
__cn
__co
__component
__compound
__cond
__convert
__delete
__dl
__dv
__eq
__er
__ge
__gt
__indirect
__le
__ls
__lt
__max
__md
__method_call
__mi
__min
__minus
__ml
__mm
__mn
__mult
__mx
__ne
__negate
__new
__nop
__nt
__nw
__oo
__op
__or
__pl
__plus
__postdecrement
__postincrement
__pp
__pt
__rf
__rm
__rs
__sz
__trunc_div
__trunc_mod
__truth_andif
__truth_not
__truth_orif
__vc
__vd
__vn
SGI badnames:
__builtin_alloca
__builtin_fsqrt
__builtin_sqrt
__builtin_fabs
__builtin_dabs
__builtin_cast_f2i
__builtin_cast_i2f
__builtin_cast_d2ll
__builtin_cast_ll2d
__builtin_copy_dhi2i
__builtin_copy_i2dhi
__builtin_copy_dlo2i
__builtin_copy_i2dlo
__add_and_fetch
__sub_and_fetch
__or_and_fetch
__xor_and_fetch
__and_and_fetch
__nand_and_fetch
__mpy_and_fetch
__min_and_fetch
__max_and_fetch
__fetch_and_add
__fetch_and_sub
__fetch_and_or
__fetch_and_xor
__fetch_and_and
__fetch_and_nand
__fetch_and_mpy
__fetch_and_min
__fetch_and_max
__lock_test_and_set
__lock_release
__lock_acquire
__compare_and_swap
__synchronize
__high_multiply
__unix
__sgi
__linux__
__i386__
__i486__
__cplusplus
__embedded_cplusplus
// long double conversion members mangled as __opr
// http://gcc.gnu.org/ml/libstdc++/1999-q4/msg00060.html
__opr
By Example
This library is written to appropriate C++ coding standards. As such,
it is intended to precede the recommendations of the GNU Coding
Standard, which can be referenced in full here:
http://www.gnu.org/prep/standards/standards.html#Formatting
The rest of this is also interesting reading, but skip the "Design
Advice" part.
The GCC coding conventions are here, and are also useful:
http://gcc.gnu.org/codingconventions.html
In addition, because it doesn't seem to be stated explicitly anywhere
else, there is an 80 column source limit.
ChangeLog
entries for member functions should use the
classname::member function name syntax as follows:
1999-04-15 Dennis Ritchie <dr@att.com>
* src/basic_file.cc (__basic_file::open): Fix thinko in
_G_HAVE_IO_FILE_OPEN bits.
Notable areas of divergence from what may be previous local practice
(particularly for GNU C) include:
01. Pointers and references
char* p = "flop";
char& c = *p;
-NOT-
char *p = "flop"; // wrong
char &c = *p; // wrong
Reason: In C++, definitions are mixed with executable code. Here,
p
is being initialized, not *p
. This is near-universal
practice among C++ programmers; it is normal for C hackers
to switch spontaneously as they gain experience.
02. Operator names and parentheses
operator==(type)
-NOT-
operator == (type) // wrong
Reason: The ==
is part of the function name. Separating
it makes the declaration look like an expression.
03. Function names and parentheses
void mangle()
-NOT-
void mangle () // wrong
Reason: no space before parentheses (except after a control-flow
keyword) is near-universal practice for C++. It identifies the
parentheses as the function-call operator or declarator, as
opposed to an expression or other overloaded use of parentheses.
04. Template function indentation
template<typename T>
void
template_function(args)
{ }
-NOT-
template<class T>
void template_function(args) {};
Reason: In class definitions, without indentation whitespace is
needed both above and below the declaration to distinguish
it visually from other members. (Also, re: "typename"
rather than "class".) T
often could be int
, which is
not a class. ("class", here, is an anachronism.)
05. Template class indentation
template<typename _CharT, typename _Traits>
class basic_ios : public ios_base
{
public:
// Types:
};
-NOT-
template<class _CharT, class _Traits>
class basic_ios : public ios_base
{
public:
// Types:
};
-NOT-
template<class _CharT, class _Traits>
class basic_ios : public ios_base
{
public:
// Types:
};
06. Enumerators
enum
{
space = _ISspace,
print = _ISprint,
cntrl = _IScntrl
};
-NOT-
enum { space = _ISspace, print = _ISprint, cntrl = _IScntrl };
07. Member initialization lists
All one line, separate from class name.
gribble::gribble()
: _M_private_data(0), _M_more_stuff(0), _M_helper(0)
{ }
-NOT-
gribble::gribble() : _M_private_data(0), _M_more_stuff(0), _M_helper(0)
{ }
08. Try/Catch blocks
try
{
//
}
catch (...)
{
//
}
-NOT-
try {
//
} catch(...) {
//
}
09. Member functions declarations and definitions
Keywords such as extern, static, export, explicit, inline, etc
go on the line above the function name. Thus
virtual int
foo()
-NOT-
virtual int foo()
Reason: GNU coding conventions dictate return types for functions
are on a separate line than the function name and parameter list
for definitions. For C++, where we have member functions that can
be either inline definitions or declarations, keeping to this
standard allows all member function names for a given class to be
aligned to the same margin, increasing readability.
10. Invocation of member functions with "this->"
For non-uglified names, use this->name
to call the function.
this->sync()
-NOT-
sync()
Reason: Koenig lookup.
11. Namespaces
namespace std
{
blah blah blah;
} // namespace std
-NOT-
namespace std {
blah blah blah;
} // namespace std
12. Spacing under protected and private in class declarations:
space above, none below
i.e.
public:
int foo;
-NOT-
public:
int foo;
13. Spacing WRT return statements.
no extra spacing before returns, no parenthesis
i.e.
}
return __ret;
-NOT-
}
return __ret;
-NOT-
}
return (__ret);
14. Location of global variables.
All global variables of class type, whether in the "user visible"
space (e.g., cin
) or the implementation namespace, must be defined
as a character array with the appropriate alignment and then later
re-initialized to the correct value.
This is due to startup issues on certain platforms, such as AIX.
For more explanation and examples, see src/globals.cc
. All such
variables should be contained in that file, for simplicity.
15. Exception abstractions
Use the exception abstractions found in functexcept.h
, which allow
C++ programmers to use this library with -fno-exceptions
. (Even if
that is rarely advisable, it's a necessary evil for backwards
compatibility.)
16. Exception error messages
All start with the name of the function where the exception is
thrown, and then (optional) descriptive text is added. Example:
__throw_logic_error(__N("basic_string::_S_construct NULL not valid"));
Reason: The verbose terminate handler prints out exception::what()
,
as well as the typeinfo for the thrown exception. As this is the
default terminate handler, by putting location info into the
exception string, a very useful error message is printed out for
uncaught exceptions. So useful, in fact, that non-programmers can
give useful error messages, and programmers can intelligently
speculate what went wrong without even using a debugger.
17. The doxygen style guide to comments is a separate document,
see index.
The library currently has a mixture of GNU-C and modern C++ coding
styles. The GNU C usages will be combed out gradually.
Name patterns:
For nonstandard names appearing in Standard headers, we are constrained
to use names that begin with underscores. This is called "uglification".
The convention is:
Local and argument names: __[a-z].*
Examples: __count __ix __s1
Type names and template formal-argument names: _[A-Z][^_].*
Examples: _Helper _CharT _N
Member data and function names: _M_.*
Examples: _M_num_elements _M_initialize ()
Static data members, constants, and enumerations: _S_.*
Examples: _S_max_elements _S_default_value
Don't use names in the same scope that differ only in the prefix,
e.g. _S_top and _M_top. See BADNAMES for a list of forbidden names.
(The most tempting of these seem to be and "_T" and "__sz".)
Names must never have "__" internally; it would confuse name
unmanglers on some targets. Also, never use "__[0-9]", same reason.
--------------------------
[BY EXAMPLE]
#ifndef _HEADER_
#define _HEADER_ 1
namespace std
{
class gribble
{
public:
gribble() throw();
gribble(const gribble&);
explicit
gribble(int __howmany);
gribble&
operator=(const gribble&);
virtual
~gribble() throw ();
// Start with a capital letter, end with a period.
inline void
public_member(const char* __arg) const;
// In-class function definitions should be restricted to one-liners.
int
one_line() { return 0 }
int
two_lines(const char* arg)
{ return strchr(arg, 'a'); }
inline int
three_lines(); // inline, but defined below.
// Note indentation.
template<typename _Formal_argument>
void
public_template() const throw();
template<typename _Iterator>
void
other_template();
private:
class _Helper;
int _M_private_data;
int _M_more_stuff;
_Helper* _M_helper;
int _M_private_function();
enum _Enum
{
_S_one,
_S_two
};
static void
_S_initialize_library();
};
// More-or-less-standard language features described by lack, not presence.
# ifndef _G_NO_LONGLONG
extern long long _G_global_with_a_good_long_name; // avoid globals!
# endif
// Avoid in-class inline definitions, define separately;
// likewise for member class definitions:
inline int
gribble::public_member() const
{ int __local = 0; return __local; }
class gribble::_Helper
{
int _M_stuff;
friend class gribble;
};
}
// Names beginning with "__": only for arguments and
// local variables; never use "__" in a type name, or
// within any name; never use "__[0-9]".
#endif /* _HEADER_ */
namespace std
{
template<typename T> // notice: "typename", not "class", no space
long_return_value_type<with_many, args>
function_name(char* pointer, // "char *pointer" is wrong.
char* argument,
const Reference& ref)
{
// int a_local; /* wrong; see below. */
if (test)
{
nested code
}
int a_local = 0; // declare variable at first use.
// char a, b, *p; /* wrong */
char a = 'a';
char b = a + 1;
char* c = "abc"; // each variable goes on its own line, always.
// except maybe here...
for (unsigned i = 0, mask = 1; mask; ++i, mask <<= 1) {
// ...
}
}
gribble::gribble()
: _M_private_data(0), _M_more_stuff(0), _M_helper(0)
{ }
int
gribble::three_lines()
{
// doesn't fit in one line.
}
} // namespace std