Some sections of the Lumiera website document meeting minutes, discussion protocols and design proposals from the early days of the project; these pages were initially authored in the »Moin Moin Wiki« operated by Cehteh on pipapo.org at that time; this wiki backed the first publications of the »Cinelerra-3« initiative, which turned into the Lumiera project eventually. Some years later, those pages were transliterated into Asciidoc semi-automatically, resulting in a lot of broken markup and links. This is a long standing maintenance problem problem plaguing the Lumiera website, since those breakages cause a lot of warnings and flood the logs of any linkchecker run.
216 lines
7.8 KiB
Text
216 lines
7.8 KiB
Text
Design Process : C Coding Style Guide
|
|
=====================================
|
|
|
|
[options="autowidth"]
|
|
|====================================
|
|
|*State* | _Final_
|
|
|*Date* | _2007-07-03_
|
|
|*Proposed by* | ct
|
|
|====================================
|
|
|
|
|
|
|
|
|
|
C Coding Style Guide
|
|
--------------------
|
|
I introduce here my favorite C coding style.
|
|
|
|
|
|
|
|
|
|
Description
|
|
~~~~~~~~~~~
|
|
In the following I'll explain a C coding style I used frequently for other
|
|
projects. Take this as suggestion for parts written in C (it definitely makes
|
|
no sense for C++). We probably don't need to enforce this style for normal C
|
|
code, but for the related
|
|
link:{rfc}/AllPluginInterfacesAreC.html[Rfc: »All Plugin Interfaces Are C«]
|
|
it really makes sense to have some well defined style.
|
|
|
|
|
|
Function names follow the rule:
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
.`namespace[\_object][\_verb[\_subjects]][\_version]`
|
|
* namespace is `lumiera_` appended with some subsystem tag
|
|
(`lumiera_plugin_audio_`)
|
|
* object is the type of the `this' (or `self') object we are addressing,
|
|
maybe followed by the object we are returning
|
|
* verb is the action to take, (new, copy, free, set, clear,.. etc.) if omitted
|
|
the action is `get`
|
|
* subjects is a descriptive list of the arguments which the action takes, this
|
|
should be a human readable word describing the parameter concept, and NOT
|
|
encoding a concrete type (name, age, weight; not string, int, float)
|
|
* for interfaces we may use versioning, then a number is appended to the name
|
|
but we alias the actual function with a inline function or a macro without
|
|
this number.
|
|
|
|
|
|
Prototypes follow the rule:
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
.`rettype function (Object self, ...)`
|
|
* function is the functionname as above
|
|
* rettype is sensible to what object and verb define, setters return a pointer
|
|
to the set'ed element if an allocation could be involved (or NULL on
|
|
failure), a int if the setter does some checks over the supplied argument
|
|
(`0` indicates failure, `!0` success), void for procedures and actions which can
|
|
never fail.
|
|
* Object is a pointer to referred object (`this' like C++) in rare cases
|
|
(`_new()`) functions may be used without this self pointer, see below
|
|
* `...` are the types and names of the arguments described in `subjects` of the
|
|
name.
|
|
|
|
|
|
Object variants:
|
|
^^^^^^^^^^^^^^^^
|
|
For each `struct namespace_foo_struct` we have following typedefs:
|
|
|
|
[source,C]
|
|
----
|
|
typedef struct namespace_foo_struct namespace_foo; // basic struct name
|
|
typedef namespace_foo* NamespaceFoo; // canonical object pointer/handle
|
|
typedef const namespace_foo * const_NamespaceFoo; // pointer to const object
|
|
typedef namespace_foo ** NamespaceFoo_ref; // when intend to mutate the handle itself
|
|
typedef const namespace_foo ** const_NamespaceFoo_ref; // same for const object handle
|
|
----
|
|
|
|
Examples:
|
|
+++++++++
|
|
.`lumiera_plugin_audio_sample_normalize_limit_1 (AudioSample self, int limit)`
|
|
* namespace is `lumiera_plugin_audio`
|
|
* operates on a `sample' object (and likely returns a pointer)
|
|
* operation is `normalize`
|
|
* takes one additional parameter describing the limit for normalization
|
|
* this is a version 1 interface we later define:
|
|
|
|
[source,C]
|
|
----
|
|
#define lumiera_plugin_audio_sample_normalize_limit\
|
|
lumiera_plugin_audio_sample_normalize_limit_1
|
|
----
|
|
|
|
.`lumiera_plugin_audio_sample_rate_1 (AudioSample self)`
|
|
* this would be just a getter function returning the sample rate
|
|
|
|
.`lumiera_plugin_audio_sample_set_rate_1 (AudioSample self, unsigned rate)`
|
|
* a setter, note that the 'rate' is defined after the verb
|
|
|
|
|
|
|
|
|
|
|
|
Pros
|
|
^^^^
|
|
* supplements documentation, makes it even unneeded sometimes
|
|
* well defined namespace
|
|
* C language bindings without tricks
|
|
|
|
|
|
Cons
|
|
^^^^
|
|
* very long identifier names
|
|
* not completely unique
|
|
|
|
|
|
Alternatives
|
|
^^^^^^^^^^^^
|
|
* Hungarian notation isn't readable, fails semantic consistency, has renaming
|
|
issues and encodes types rather than concepts. There are simpler schemes
|
|
which are even more unambiguous.
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
~~~~~~~~~
|
|
I am trying/using this scheme since some time now, at first it looks like
|
|
overhead to encode arguments to functionnames. But the intention here is to
|
|
make code easy readable and memorizeable, when one follows this scheme one does
|
|
seldom need to lookup the docs about the API. In fact it sometimes even turns
|
|
out that one wants to use a functionname which isn't defined in the API, which
|
|
is a good indicator to add such a missing function to the API.
|
|
|
|
This scheme is not fully unambiguous but suffices for all practical task. It
|
|
encodes parameters like C++ does for overloading without strange mangling. All
|
|
names are global in a well defined namespace which is very natural for C (other
|
|
OO like C styles involve structs and hand written CTables, with this scheme we
|
|
trampoline from this global names to VTables _only if needed_)
|
|
|
|
|
|
|
|
|
|
Conclusion
|
|
----------
|
|
Finalized at the link:{ldoc}/devel/meeting_summary/2008-03-06.html[2008-03-06 developer meeting]
|
|
|
|
|
|
|
|
|
|
Comments
|
|
--------
|
|
|
|
I strongly object promoting such a scheme as a general ``Style Guide''. It can be
|
|
a help or last resort if you are forced to work with improper tools (a
|
|
situation that's rather frequent in practice though). __As such it is well
|
|
chosen and practical__, however.
|
|
|
|
But basically, it shows several things:
|
|
|
|
* you are using a global namespace
|
|
* you deal with way to fat interfaces
|
|
* you mix deployment metadata (a version/compatibility check) with functional
|
|
code
|
|
|
|
All of this indicates some design style breakage, so it would be preferable to
|
|
fix the design if possible.
|
|
|
|
The only part I'd like to support as a Style Guide is the rule of using the
|
|
"verb+object" pattern for creating function names
|
|
|
|
Ichthyostega:: '2007-07-08T11:42:39Z'
|
|
|
|
Probably needs little explanation:
|
|
|
|
* you are using a global namespace
|
|
|
|
** This is only about C for names which get exported, C only has a global
|
|
namespace and we need some way to get unique names. The
|
|
link:{rfc}/AllPluginInterfacesAreC.html[RfC: Plugin Interfaces in C]
|
|
already uses better/smaller namespaces by defining interfaces as C structs.
|
|
The full blown long names explained here are technically not needed when we use
|
|
the plugin system as proposed, I just shown them here for completeness. Next,
|
|
when we decide for alternative linking methods like static builds we would need to
|
|
declare all "verb+object" functions static, else there is a high probability of
|
|
clashes.
|
|
|
|
* you deal with way to fat interfaces
|
|
|
|
** How can you tell that? This is only a nameing style. No interfaces mentioned
|
|
here. I am all after small well defined specialized interfaces.
|
|
|
|
* you mix deployment metadata (a version/compatibility check) with functional code
|
|
|
|
** Yes, I cant figure out how to do it better but still lightweight in C. the
|
|
`_version` thing is something I added here after the interfaces proposal. I work
|
|
on a example how this will be used in a more friendly way.
|
|
|
|
Note again that this is a ``naming system'', it is intended to be very verbose
|
|
and give unique declarative names. It is not about design! Design is done as
|
|
usual and only when things have to be exported as C symbols (both, exported and
|
|
C!!) this applies. This has zero implication for C++ code, zero implication
|
|
for C functions which are not exported (while I personally still prefer this
|
|
style) and finally when we do the interfaces thing like I proposed, then the
|
|
naming can be much simpler, see examples there or in my repository.
|
|
|
|
ct:: '2007-07-10T08:03:06Z'
|
|
|
|
|
|
Thanks, your explanation together with the example in git made the usage
|
|
pattern much more clear. I think the `_version` postfix is esp. helpful on the
|
|
names of the plugin interfaces (structs in C), and probably it will be a good
|
|
practice, to have one such common plugin interface on every ``plugin extension
|
|
point'', i.e. every point in the system, that can be extended by plugins.
|
|
|
|
Ichthyostega:: '2007-07-10T17:23:33Z'
|
|
|
|
''''
|
|
Back to link:/x/DesignProcess.html[Lumiera Design Process overview]
|