diff --git a/bacnet-stack/doc/code-standard.txt b/bacnet-stack/doc/code-standard.txt new file mode 100644 index 00000000..749c9776 --- /dev/null +++ b/bacnet-stack/doc/code-standard.txt @@ -0,0 +1,211 @@ +This software runs on many platforms, and can be compiled with a number of +different compilers; here are some rules for writing code that will work +on multiple platforms. + +Don't use C++-style comments (comments beginning with "//" and running +to the end of the line) for modules that are written in C. The module +may run through C rather than C++ compilers, and not all C compilers +support C++-style comments (GCC does, but IBM's C compiler for AIX, for +example, doesn't do so by default). + +Don't initialize variables in their declaration with non-constant +values. Not all compilers support this. E.g. don't use + uint32_t i = somearray[2]; +use + uint32_t i; + i = somearray[2]; +instead. + +Don't use zero-length arrays; not all compilers support them. If an +array would have no members, just leave it out. + +Don't declare variables in the middle of executable code; not all C +compilers support that. Variables should be declared at the beginning +of a function or compound statement, or outside a function + +Don't use "inline"; not all compilers support it. + +Use the C99 stdint.h and stdbool.h definitions for declaring variables +when needed. If they are not defined for your compiler, put those files +into the ports directory for your compiler with the proper definitions. +Sometimes scalable code should just use an int or unsigned declaration. +8-bit unsigned = uint8_t +8-bit signed = int8_t +16-bit unsigned = uint16_t +16-bit signed = int16_t +32-bit unsigned = uint32_t +32-bit signed = int32_t +boolean = bool + +Don't use "long" to mean "signed 32-bit integer", and don't use +"unsigned long" to mean "unsigned 32-bit integer"; "long"s are 64 bits +long on many platforms. Use "int32_t" for signed 32-bit integers and use +"uint32_t" for unsigned 32-bit integers. + +Don't use "long" to mean "signed 64-bit integer" and don't use "unsigned +long" to mean "unsigned 64-bit integer"; "long"s are 32 bits long on +many other platforms. Don't use "long long" or "unsigned long long", +either, as not all platforms support them; use "int64_t" or "uint64_t", +which need to be defined as the appropriate types for 64-bit signed and +unsigned integers. + +Don't use a label without a statement following it. For example, +something such as + + if (...) { + + ... + + done: + } + +will not work with all compilers - you have to do + + if (...) { + + ... + + done: + ; + } + +with some statements, even if it's a null statement, after the label. + +Don't use "bzero()", "bcopy()", or "bcmp()"; instead, use the ANSI C +routines + + "memset()" (with zero as the second argument, so that it sets + all the bytes to zero); + + "memcpy()" or "memmove()" (note that the first and second + arguments to "memcpy()" are in the reverse order to the + arguments to "bcopy()"; note also that "bcopy()" is typically + guaranteed to work on overlapping memory regions, while + "memcpy()" isn't, so if you may be copying from one region to a + region that overlaps it, use "memmove()", not "memcpy()" - but + "memcpy()" might be faster as a result of not guaranteeing + correct operation on overlapping memory regions); + + and "memcmp()" (note that "memcmp()" returns 0, 1, or -1, doing + an ordered comparison, rather than just returning 0 for "equal" + and 1 for "not equal", as "bcmp()" does). + +Not all platforms necessarily have "bzero()"/"bcopy()"/"bcmp()", and +those that do might not declare them in the header file on which they're +declared on your platform. + +Don't use "index()" or "rindex()"; instead, use the ANSI C equivalents, +"strchr()" and "strrchr()". Not all platforms necessarily have +"index()" or "rindex()", and those that do might not declare them in the +header file on which they're declared on your platform. + +Don't fetch data from packets by getting a pointer to data in the +packet, casting that pointer to a pointer to a structure, +and dereferencing that pointer. That pointer won't necessarily be aligned +on the proper boundary, which can cause crashes on some platforms (even +if it doesn't crash on an x86-based PC). This means that you cannot +safely cast it to any data type other than a pointer to "char", +"unsigned char", "uint8_t", or other one-byte data types. You cannot, +for example, safely cast it to a pointer to a structure, and then access +the structure members directly; on some systems, unaligned accesses to +integral data types larger than 1 byte, and floating-point data types, +cause a trap, which will, at best, result in the OS slowly performing an +unaligned access for you, and will, on at least some platforms, cause +the program to be terminated. + +The data in a packet is not necessarily in the byte order of +the machine on which this software is running. Make use of +big_endian() which returns non-zero on big_endian machines. + +Use "ntohs()", "ntohl()", "htons()", or "htonl()" only in the ports +directories since the header files required to define or declare +them differ between platforms. There are some common functions in +the bacdcode library for converting to and from long and short. + +Don't put a comma after the last element of an enum - some compilers may +either warn about it (producing extra noise) or refuse to accept it. + +When opening a file with "fopen()", "freopen()", or "fdopen()", if the +file contains ASCII text, use "r", "w", "a", and so on as the open mode +- but if it contains binary data, use "rb", "wb", and so on. On +Windows, if a file is opened in a text mode, writing a byte with the +value of octal 12 (newline) to the file causes two bytes, one with the +value octal 15 (carriage return) and one with the value octal 12, to be +written to the file, and causes bytes with the value octal 15 to be +discarded when reading the file (to translate between C's UNIX-style +lines that end with newline and Windows' DEC-style lines that end with +carriage return/line feed). + +In addition, that also means that when opening or creating a binary +file, you must use "open()" (with O_CREAT and possibly O_TRUNC if the +file is to be created if it doesn't exist), and OR in the O_BINARY flag. +That flag is not present on most, if not all, UNIX systems, so you must +also do + + #ifndef O_BINARY + #define O_BINARY 0 + #endif + +to properly define it for UNIX (it's not necessary on UNIX). + +Don't use forward declarations of static arrays without a specified size +in a fashion such as this: + + static const value_string foo_vals[]; + + ... + + static const value_string foo_vals[] = { + { 0, "Red" }, + { 1, "Green" }, + { 2, "Blue" }, + { 0, NULL } + }; + +as some compilers will reject the first of those statements. Instead, +initialize the array at the point at which it's first declared, so that +the size is known. + +Don't put declarations in the middle of a block; put them before all +code. Not all compilers support declarations in the middle of code, +such as + + int i; + + i = foo(); + + int j; + +For #define names and enum member names, prefix the names with a tag so +as to avoid collisions with other names - this might be more of an issue +on Windows, as it appears to #define names such as DELETE and +OPTIONAL. + +Don't use "variadic macros", such as + + #define DBG(format, args...) fprintf(stderr, format, ## args) + +as not all C compilers support them. Use macros that take a fixed +number of arguments, such as + + #define DBG0(format) fprintf(stderr, format) + #define DBG1(format, arg1) fprintf(stderr, format, arg1) + #define DBG2(format, arg1, arg2) fprintf(stderr, format, arg1, arg2) + + ... + +or something such as + + #define DBG(args) printf args + +Instead of tmpnam(), use mkstemp(). tmpnam is insecure and should +not be used any more. Note: mkstemp does not accept NULL as a parameter. + +Try to write code portably whenever possible, however; note that +there are some routines in the software that are platform-dependent +implementations. The platform independent API is declared in the +header file, and the dependent routine is placed in a ports directory. + +Reference: The cross platform aspect of this coding standard is based +on the developer coding standard for Ethereal and has been modified +by Steve Karg for this project. Thank you, Ethereal!