Open main menu

Difference between revisions of "Coding Conventions"

2,862 bytes added ,  09:22, 11 April 2011
Added comments on global vars (not finished)
m (moved Portability Guide to Coding Conventions: We may need to cover coding conventions that are not strictly about portability, such as the conventions on "static" variables which cause problems with RTL.)
(Added comments on global vars (not finished))
Line 1: Line 1:
Portability to as many systems as possible is one of the primary design goals of ScummVM. We strive all the time to ensure our code compiles and runs on as many systems as possible. To this end, it's important that our developers are aware of certain typical portability problems and pitfalls. On this page we try to collect some of them.
On this page, we collect some coding conventions that anybody who works on ScummVM, and anybody who would like to submit a patch, should read and adhere to.


Work in progress: This page is incomplete. We should probably also link on some good & relevant web pages on the net, and only focus on the most frequent or maybe unusual (ScummVM specific) issues.
Many of these are all about ''portability'' of the code to as many systems as possible. This is one of the primary design goals of ScummVM. It means that we strive to ensure our code compiles and runs on as many systems as possible. On this page we try to collect typical portability problems and pitfalls, and how to avoid them.
 
Beyond that, there are other caveats that we point out. For example things that make engines non-reentrant (which causes problems when using the "return to launcher" feature, and then resuming a game).
 
''TODO: This page is incomplete. We should probably also link on some good & relevant web pages on the net, and only focus on the most frequent or maybe unusual (ScummVM specific) issues.''




== Language features ==
== Language features ==
ScummVM is written in a subset of C++. Due to limitations of the C++ run-times on various platforms, the following features cannot be used:
ScummVM is written in a subset of C++. Due to limitations of the C++ run-times on various platforms, the following features cannot currently be used:
* C++ exceptions (throw/catch): Not all C++ compilers support these correctly (esp. on embedded systems), and exception support incurs a noticeable overhead in binary size.
* C++ exceptions (throw/catch): Not all C++ compilers support these correctly (esp. on embedded systems), and exception support incurs a noticeable overhead in binary size.
* C++ RTTI (run-time type information, as in dynamic_cast<>): This incurs a severe overhead in binary size and memory usage, as every C++ object is enlarged by RTTI information
* C++ RTTI (run-time type information, as in dynamic_cast<>): This incurs a severe overhead in binary size and memory usage, as every C++ object is enlarged by RTTI information
Line 34: Line 38:
== File access ==
== File access ==
In a nutshell, you must not use fopen(), fread(), fwrite(), etc., nor open(), close(), etc. in your code (unless you are developing a backend, that is). Instead you must use the APIs for reading and writing files provided by ScummVM. Please consult the [[HOWTO-Open Files|HOWTO Open Files]] page for details.
In a nutshell, you must not use fopen(), fread(), fwrite(), etc., nor open(), close(), etc. in your code (unless you are developing a backend, that is). Instead you must use the APIs for reading and writing files provided by ScummVM. Please consult the [[HOWTO-Open Files|HOWTO Open Files]] page for details.
== Use of global / static variables ==
There are two major issues with global variables (and that includes static variables hidden inside function bodies, too). In general, you should therefore avoid them whenever possible. These affect mainly frontend code, though (engines, GUI code, common code), backends authors have more liberties in this regard.
The first issue are global variables of a type that requires a constructor. The problem with that is multifold. E.g. the order in which such global constructors are invoked is not well-defined in general. So things may work fine on one system but bad on another. Next, engines can be compiled into dynamically loadable plugins. So when the plugin is loaded, the constructors of global objects in that plugin may or may not be called, depending on the code loader in use. Likewise, when the plugin is unloaded, destructors may or may not be called.
Therefore, '''use of object requiring global constructors is forbidden in ScummVM'''. Developers are encouraged to compile their code with the "-Wglobal-destructors" option (when using GCC or clang), combined with -Werror. Exceptions may be possible for backend code, but even there we advice them to be avoided.
The second issue concerns problems causing engines to be non-reentrant. Consider a code snippet like this:
<syntax type="C++">
  bool foo(bool cond) {
    static bool bar = false;
    if (cond)
      bar = true;
    return bar;
  }
</syntax>
Suppose this function is part of engine quux. When a new game using this engine is started, foo(false) will initially always return false. After foo(true) has been called the first time, foo will always return true. Maybe foo(true) is called when the user/player solves a certain puzzle in the game, and maybe the foo() function is meant to test whether this puzzle has already been solved.
Now imagine the player uses the "return to launcher" feature; once back in the launcher, they restart the game, again using the quux engine.
Now the static global variable inside foo() has not been reset! As a consequence, the engine will still think that puzzle has been solved, even though a completely new game was started.
This is another important reason why global variables keeping state are dangerous. At the very least, you ''must'' re-init any global variables whenever your engine starts. Relying on one-time initialization assignments to global variables, as in
<syntax type="C++">
  static int myGlobal = 0;
</syntax>
is ''not'' sufficient.
1,079

edits