Project

General

Profile

Object Oriented C programming style » History » Version 8

Tobias Brunner, 21.06.2016 15:35
Some details about our OO design

1 4 Andreas Steffen
h1. Object Oriented C programming style
2 4 Andreas Steffen
3 1 Martin Willi
For new code in strongSwan, we use an object oriented programming style. This allows us to employ modern programming paradigms, but still use the standard C compiler and toolset.
4 1 Martin Willi
5 4 Andreas Steffen
6 4 Andreas Steffen
h2. Concept
7 4 Andreas Steffen
8 7 Graham Hudspith
This object oriented design is achieved by heavy use of function pointers. Interfaces of classes are defined as a struct with function pointers, and an implementation extends the struct by including the Interface as its first struct member. The idea is based on the coding style of the "xine project":http://www.xine-project.org/hackersguide#id324430.
9 1 Martin Willi
To get an idea of the whole concept we recommend to examine the code directly.
10 1 Martin Willi
11 6 Martin Willi
h2. Type safety
12 1 Martin Willi
13 8 Tobias Brunner
To achieve type safety without casting the _this_ parameter in each method, we have introduced some special helper macros. The @METHOD@ macro helps in implementing a method that is compatible to both the public and the private interfaces automatically. The @INIT@ macro initializes objects using readable _Designated Initializers_, which also ensure that all members that are not explicitly initialized are set to zero.
14 8 Tobias Brunner
15 8 Tobias Brunner
h2. Details and Examples
16 8 Tobias Brunner
17 8 Tobias Brunner
The following explanations and examples are from the _xine_ docs but are slightly adapted to better match our code style (refer to our actual code for concrete examples).
18 8 Tobias Brunner
19 8 Tobias Brunner
{{collapse(Details and Examples)
20 8 Tobias Brunner
Classes are structs containing function pointers and public member data. Example:
21 8 Tobias Brunner
<pre>
22 8 Tobias Brunner
typedef struct my_stack_t my_stack_t;
23 8 Tobias Brunner
 
24 8 Tobias Brunner
struct my_stack_t {
25 8 Tobias Brunner
26 8 Tobias Brunner
	/**
27 8 Tobias Brunner
	 * Method "push" with one parameter and no return value
28 8 Tobias Brunner
	 *	
29 8 Tobias Brunner
	 * @param i	element to push
30 8 Tobias Brunner
	 */
31 8 Tobias Brunner
	void (*push)(my_stack_t *this, int i);
32 8 Tobias Brunner
   
33 8 Tobias Brunner
	/**
34 8 Tobias Brunner
	 * Method "add" with no parameters and no return value
35 8 Tobias Brunner
	 */
36 8 Tobias Brunner
	void (*add)(my_stack_t *this);
37 8 Tobias Brunner
   
38 8 Tobias Brunner
	/**
39 8 Tobias Brunner
	 * Method "pop" with no parameters (except "this") and a return value
40 8 Tobias Brunner
	 *
41 8 Tobias Brunner
	 * @return	popped element
42 8 Tobias Brunner
	 */
43 8 Tobias Brunner
	int (*pop)(my_stack_t *this);
44 8 Tobias Brunner
};
45 8 Tobias Brunner
46 8 Tobias Brunner
/**
47 8 Tobias Brunner
 * Constructor
48 8 Tobias Brunner
 *
49 8 Tobias Brunner
 * @return	instance of my_stack_t
50 8 Tobias Brunner
 */
51 8 Tobias Brunner
my_stack_t *my_stack_create();
52 8 Tobias Brunner
</pre>
53 8 Tobias Brunner
54 8 Tobias Brunner
To derive from such a class, private member variables can be added:
55 8 Tobias Brunner
56 8 Tobias Brunner
<pre>
57 8 Tobias Brunner
typedef private_my_stack_t private_my_stack_t;
58 8 Tobias Brunner
59 8 Tobias Brunner
struct private_my_stack_t {
60 8 Tobias Brunner
61 8 Tobias Brunner
	/**
62 8 Tobias Brunner
	 * Public interface
63 8 Tobias Brunner
	 */
64 8 Tobias Brunner
	my_stack_t public;
65 8 Tobias Brunner
    
66 8 Tobias Brunner
	/**
67 8 Tobias Brunner
	 * Internal stack items
68 8 Tobias Brunner
	 */
69 8 Tobias Brunner
	int values[MAX_STACK_SIZE];
70 8 Tobias Brunner
71 8 Tobias Brunner
	/**
72 8 Tobias Brunner
	 * Number of items
73 8 Tobias Brunner
	 */
74 8 Tobias Brunner
	int stack_size;
75 8 Tobias Brunner
};
76 8 Tobias Brunner
</pre>
77 8 Tobias Brunner
78 8 Tobias Brunner
Each method is implemented as a static method (static to prevent namespace pollution) using the @METHOD@ macro (which defines @_<method_name>@ with the public signature for use in the constructor).
79 8 Tobias Brunner
80 8 Tobias Brunner
Implementation of the "push" method:
81 8 Tobias Brunner
<pre>
82 8 Tobias Brunner
METHOD(my_stack_t, push, void,
83 8 Tobias Brunner
	private_my_stack_t *this, int i)
84 8 Tobias Brunner
{
85 8 Tobias Brunner
	this->values[MAX_STACK_SIZE - ++this->stack_size] = i;
86 8 Tobias Brunner
}
87 8 Tobias Brunner
</pre>
88 8 Tobias Brunner
89 8 Tobias Brunner
Finally the contructor uses the @INIT@ macro to allocate an instance of the private struct and fills the function pointers and default values (using designated initializers). Usually the constructor is the only public (i.e. non-static) function in the module:
90 8 Tobias Brunner
91 8 Tobias Brunner
<pre>
92 8 Tobias Brunner
my_stack_t *my_stack_create()
93 8 Tobias Brunner
{
94 8 Tobias Brunner
	private_my_stack_t *this;
95 8 Tobias Brunner
96 8 Tobias Brunner
	INIT(this,
97 8 Tobias Brunner
		.public = {
98 8 Tobias Brunner
			.push = _push,
99 8 Tobias Brunner
			.add = _add,
100 8 Tobias Brunner
			.pop = _pop,
101 8 Tobias Brunner
		},
102 8 Tobias Brunner
		/* uninitialized fields are automatically set to zero */
103 8 Tobias Brunner
	);
104 8 Tobias Brunner
   
105 8 Tobias Brunner
	/* return public part */
106 8 Tobias Brunner
	return &this->public;
107 8 Tobias Brunner
}
108 8 Tobias Brunner
</pre>
109 8 Tobias Brunner
}}
110 4 Andreas Steffen
111 1 Martin Willi
h2. Gedit Snippets
112 4 Andreas Steffen
113 5 Tobias Brunner
Being a gedit user, I created some snippets (attachment:gedit-snippets-strongswan.tar.gz) to create interfaces, methods (including implementations and pointer assignement) and class implementations.