|
|
|
===========
|
|
|
|
Code issues
|
|
|
|
===========
|
|
|
|
|
|
|
|
This documents covers C coding issues related to Duktape implementation
|
|
|
|
such as:
|
|
|
|
|
|
|
|
* Conventions
|
|
|
|
* Portability concerns
|
|
|
|
* Specific platforms and compilers
|
|
|
|
* Size and performance optimization issues
|
|
|
|
|
|
|
|
Conventions
|
|
|
|
===========
|
|
|
|
|
|
|
|
Indentantion, naming, etc
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
Indent with tab. On continuation lines indent with tab to shared indent
|
|
|
|
depth and then indent with spaces. For example, denoting tab indent with
|
|
|
|
colon and space indent with period::
|
|
|
|
|
|
|
|
::::::::snprintf(buf,
|
|
|
|
::::::::.........sizeof(buf),
|
|
|
|
::::::::........."%d",
|
|
|
|
::::::::.........123);
|
|
|
|
|
|
|
|
Names are lowercase, underscore separated::
|
|
|
|
|
|
|
|
void duk_func(void) {
|
|
|
|
/* ... */
|
|
|
|
}
|
|
|
|
|
|
|
|
Macros are uppercase, underscore separated::
|
|
|
|
|
|
|
|
#define DUK_MACRO(x) /* ... */
|
|
|
|
|
|
|
|
Macro names must not begin with an underscore. Macros which are of local
|
|
|
|
interest only can have a local name or have a double underscore after "DUK"::
|
|
|
|
|
|
|
|
/* 'foo' alternatives, not to be used directly */
|
|
|
|
#define DUK__FOO_ALT1 /* ... */
|
|
|
|
#define DUK__FOO_ALT2 /* ... */
|
|
|
|
|
|
|
|
/* select DUK_FOO provider */
|
|
|
|
#define DUK_FOO DUK_FOO_ALT2
|
|
|
|
|
|
|
|
Comments are always traditional C comments, never ``//``::
|
|
|
|
|
|
|
|
/* always used traditional C comments */
|
|
|
|
|
|
|
|
Opening brace on the same line as the start of the construct, even
|
|
|
|
for functions::
|
|
|
|
|
|
|
|
void func(int x) {
|
|
|
|
if (x) {
|
|
|
|
/* ... */
|
|
|
|
} else {
|
|
|
|
/* ... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
The case-statements of a switch are at the same level as the switch
|
|
|
|
to reduce indent. If case clauses have their own blocks, this leads
|
|
|
|
to a confusing closing brace, so a comment for that may be in order::
|
|
|
|
|
|
|
|
switch (x) {
|
|
|
|
case A: {
|
|
|
|
/* ... */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case B: {
|
|
|
|
/* ... */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
}
|
|
|
|
} /* switch */
|
|
|
|
|
|
|
|
Space after ``if``, ``switch``, etc::
|
|
|
|
|
|
|
|
if (x) { ... } /* correct */
|
|
|
|
if(x) { ... } /* incorrect */
|
|
|
|
|
|
|
|
switch (x) { ... } /* correct */
|
|
|
|
switch(x) { ... } /* incorrect */
|
|
|
|
|
|
|
|
Use of goto for error cleanup and shared error handling is not only
|
|
|
|
allowed but encouraged.
|
|
|
|
|
|
|
|
No naked statements in e.g. ``if-then-else``, always use a block.
|
|
|
|
This is more macro compatible. Example::
|
|
|
|
|
|
|
|
if (x) {
|
|
|
|
return 1; /* correct */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x)
|
|
|
|
return 1; /* incorrect */
|
|
|
|
|
|
|
|
Multi-statement macros should use a ``do-while(0)`` construct::
|
|
|
|
|
|
|
|
#define FROBNICATE(x,y) do { \
|
|
|
|
x = x * x; \
|
|
|
|
y = y * y; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
Include guards
|
|
|
|
--------------
|
|
|
|
|
|
|
|
There are multiple include guard conventions. Leading underscores are
|
|
|
|
reserved and should be avoided in user code. The current include guard
|
|
|
|
convention is::
|
|
|
|
|
|
|
|
/* duk_foo.h */
|
|
|
|
|
|
|
|
#ifndef DUK_FOO_H_INCLUDED
|
|
|
|
#define DUK_FOO_H_INCLUDED
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
#endif /* DUK_FOO_H_INCLUDED */
|
|
|
|
|
|
|
|
http://en.wikipedia.org/wiki/Include_guard
|
|
|
|
|
|
|
|
``#pragma once`` is not portable, and is not used.
|
|
|
|
|
|
|
|
Unused variables
|
|
|
|
----------------
|
|
|
|
|
|
|
|
Suppressing unused variable warnings use the following macro::
|
|
|
|
|
|
|
|
DUK_UNREF(my_unused_var);
|
|
|
|
|
|
|
|
Internally, this currently uses the form::
|
|
|
|
|
|
|
|
(void) my_unused_var; /* suppress warning */
|
|
|
|
|
|
|
|
This seems to work with both GCC and Clang. The form::
|
|
|
|
|
|
|
|
my_unused_var = my_unused_var; /* suppress warning */
|
|
|
|
|
|
|
|
works with GCC but not with Clang.
|
|
|
|
|
|
|
|
C++ compatibility
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
The source code is meant to be C++ compatible so that you can both:
|
|
|
|
|
|
|
|
1. Compile Duktape with C but use it from C++.
|
|
|
|
|
|
|
|
2. Compile Duktape with C++ and use it from C++.
|
|
|
|
|
|
|
|
To achieve this:
|
|
|
|
|
|
|
|
* Avoid variable names conflicting with C++ keywords (``throw``,
|
|
|
|
``class``, ``this``, etc).
|
|
|
|
|
|
|
|
* Use explicit casts for all pointer conversions.
|
|
|
|
|
|
|
|
Portability concerns
|
|
|
|
====================
|
|
|
|
|
|
|
|
Platforms and compilers
|
|
|
|
=======================
|
|
|
|
|
|
|
|
VBCC
|
|
|
|
----
|
|
|
|
|
|
|
|
Even in C99 mode VBCC 0.9b:
|
|
|
|
|
|
|
|
* Does not have ``inttypes.h``.
|
|
|
|
|
|
|
|
* Does not have ``fpclassify()`` and friends.
|
|
|
|
|
|
|
|
* Does not have ``NAN`` or ``INFINITY``.
|
|
|
|
|
|
|
|
* The expression ``0.0 / 0.0`` causes a warning and results in ``0.0``
|
|
|
|
instead of ``NaN`` as expected.
|
|
|
|
|
|
|
|
* The expression ``1.0 / 0.0`` causes a warning and results in ``0.0``
|
|
|
|
instead of infinity as expected.
|
|
|
|
|
|
|
|
The following program demonstrates the NaN issue::
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
void main(void) {
|
|
|
|
double z = 0.0;
|
|
|
|
double t;
|
|
|
|
volatile union {
|
|
|
|
double d;
|
|
|
|
unsigned char b[8];
|
|
|
|
} u;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* this results in 0.0 */
|
|
|
|
t = 0.0 / 0.0;
|
|
|
|
printf("result: %lf\n", t);
|
|
|
|
|
|
|
|
/* this results in NaN */
|
|
|
|
t = z / z;
|
|
|
|
printf("result: %lf\n", t);
|
|
|
|
|
|
|
|
u.d = t;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
printf("%02x\n", u.b[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
To work with compiler optimization, the above approach needs to have the
|
|
|
|
``double`` values in ``volatile`` variables. Otherwise VBCC will end up
|
|
|
|
replacing the result with zero. So something like this is probably safest::
|
|
|
|
|
|
|
|
volatile double a = 0.0;
|
|
|
|
volatile double b = 0.0;
|
|
|
|
double t = a / b; /* -> NaN */
|
|
|
|
|