<<Home: Back to http://devdoc.net

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

      BSD adds:
      __used
      __unused
      __inline
      _Complex
      __istype
      __maskrune
      __tolower
      __toupper
      __wchar_t
      __wint_t
      _res
      _res_ext
      __tg_*

      SPU adds:
      __ea

      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