I'm trying to build documentation using doxygen 1.8.8 based on a large set of structs, and would like for the documentation to reference not only which structs I'm having, but also where the structs are used. Please note that the source code is constructed from an external system, where I do some search and replace to make it into a structure similar to the following:
struct intersect {
int aValue;
};
struct foo_intersect_SET {
order next;
foo owner;
intersect member;
};
struct intersect_bar_SET {
order next;
intersect owner;
bar member;
};
struct another_SET {
order ascending;
something owner;
foo member;
bar member2;
intersect member3;
};
I can get doxygen to build documentation, but when searching for "intersect" it only shows "intersect" and "intersect_bar_SET", I would like it to also display the "foo_intersect_SET" and possibly "another_SET".
And also when viewing the "intersect" struct I would like to get a list where it is used, i.e. that it is used by both "foo_intersect_SET", "intersect_bar_SET" and "another_SET".
Do you know if either of these are possible using doxygen?
One possible way to address this, which I'm currently pursueing is to change the structs into classes, and using multiple inheritance to get the connections both ways. In other words I have to make a temporary version which currently looks something like:
class foo : protected another {
}
class bar : proteced intersect_bar, protected another {
}
class intersect : protected foo_intersect, protected another {
int aValue;
};
class foo_intersect : private foo {
order next;
foo o_foo;
intersect m_intersect;
};
class intersect_bar : private intersect {
order next;
intersect o_intersect;
bar m_bar;
};
class another : private something {
order ascending;
something o_something;
foo m_foo;
bar m_bar;
intersect m_intersect;
};
This is not an ideal solution, but using the inheritance diagram and collaboration diagram I do get most of the information that I want out of it! One caveat is that the original set structure allows for circular definitions, which in turn leads to circular inheritance which of course is not legal...
Related
EDIT:
I think the version is known at run-time instead of compile-time so I'm not able to add it as a compile option to the gcc cmd. Which is why I have to support both versions based on whatever version the hardware reports back.
So I'm dealing with firmware where I am required to support multiple definitions for versions of the same C struct. We created our own header file as defined by the interface documentation of a memory controller based on the vendor's C struct definition.
// For simplicity lets pretend that this is the struct for version 1
typedef struct __attribute__((packed)) ver1 {
int x;
int y;
} ver1;
I also have an existing API that uses this interface already that needs to be replaced by some sort of class wrapper (I believe), or a wrapper that plays well with the existing API.
void function_call(ver1 v1);
Only one instance (ver 1 or ver 2) of the struct can exist at any time
ver 1 for a certain fw version, and ver 2 after a certain fw version
ver2 is my extended version of ver1, I am naming it as ver2 for the hope of using some sort of factory to select the right C-style struct.
typedef struct __attribute__((packed)) ver2 {
int x;
int y;
int w; // new
int z; // new
} ver2;
Before creating a ver 2 I was looking into options such as the decorator or adaptor design pattern I could try a fancy CRTP template style I found on Hands-On Design Patterns but for simplicity, I'll illustrate with this scheme where I could possibly "add-on" to ver1:
struct ver2 : public ver1 {
int w;
int z;
}
But then I learned that C++ doesn't guarantee the same class layout
C struct Inheritance vs C++ POD struct Inheritance
and potential alignment issues (I'm not too familiar with it) so I don't think it is a real option for me to use.
I found this example on stackoverflow but I don't like the idea of adding include headers in the struct How to handle conflicting struct definitions in a C application.
There is a similar example here using a similar base class
C++ design for multiple versions of same interface (enumerations / structures in header files) which I don't think I can even use due to inheritance impact on the class layout.
Unless there is a valid reason to use the techniques of the links above, I was considering a wrapper class that returns the right version based on a selector. First I'll define a free function to leverage this.
int get_fw_version(int target);
I'm working on C++11 so I'm limited on auto return type deduction and below is just some draft code I'm trying to think up, not complete, doesn't compile, just illustrating my thought process. I haven't considered composition yet since IDK how that will quite work. Looking for ideas.
int main() {
// Roughly how I would like to use it...
const int fw_ver = get_fw_version(target);
auto ver_inst = ver_factory(fw_ver);
function_call( ver_inst.get_data() );
return 0;
}
I am not sure if I can do this without polymorphism where the base class gets ver1 and but the derived class has ver2.
Rough idea where I am at, I tried doing CRTP but I hit the problem that the base class needs to be a template and I can't use a heterogeneous base type (e.g. shared_ptr). Trying the non-CRTP way IDK how to set up the abstract base class with the get_data() method. Without the compiler complains saying that the base doesn't have a get_data method, which, makes sense
// I can't figure out how to add T get_data() here without adding a template param. This base function is really to delegate common member methods and trying to keep a common base for polymorphism.
class base {
virtual ~base() = 0;
// ?? get_data() = 0 or some other method
};
class ver1_derived : public base
{
ver1 data;
public:
ver1_derived() = default;
ver1 get_data() {
return data;
}
};
class ver2_derived : public base
{
ver2 data;
public:
ver2_derived() = default;
ver2 get_data() {
return data;
}
};
// should be using unique_ptr but I can't at work....
shared_ptr<base> ver_factory(const int fw_ver) {
if(fw_ver <= 1)
return make_shared<ver1_derived>();
return make_shared<ver2_derived>();
}
I ended up giving up on an inheritance schemed and ended up taking two different code paths based on the template type.
So
if(fw_ver <= 1)
function_call<ver1>();
} else {
function_call<ver2>();
}
I am receiving the following error when trying to call the "talk" function of my DogClass:
'talk' is not a member of _DogFile.
In fact, I have declared the dog file in the _DogFileClass struct,
and in the class_init I am pointing to the talk function.
How can I access the class method from the instance of the class?
I am including the relevant code:
dog.h:
struct _DogFileClass
{
GObjectClass parent_class;
void (*talk)(DogFile *self)
}
void dog_file_talk(DogFile *self);
dog.c
void dog_file_real_talk(DogFile *self);
void dog_file_class_init(DogFileClass *klass)
{
klass->talk = dog_file_real_talk;
}
void dog_file_talk(DogFile *self)
{
g_return_if_false(DOG_IS_FILE);
DogFileClass *klass = DOG_FILE_GET_CLASS(self);
return klass->talk(self);
}
dog_file_real_talk(DogFile *self)
{
printf("WOOF")
}
and in the end I would like to use the talk function, in the following way:
dog->talk(dog);
when dog is a pointer to the DogFile class
and in the end I would like to use the talk function, in the following way: dog->talk(dog); when dog is a pointer to the DogFile class
That’s not possible, because talk is not a member of the DogFile struct. Your code in dog_file_talk() looks correct, so instead of trying to use dog->talk (dog), use dog_file_talk (dog).
I’m afraid that’s the closest you can get to OOP in C with GObject. If you were to have a talk member on the DogFile struct, that pointer would be duplicated for each instance of DogFile, which would prevent it being overrideable by subclasses, as well as being a waste of memory.
If you want more ‘natural’ OOP, use C++ (or a more modern language such as Rust) directly.
I am having a list of parameters. Each parameter is defined by an unique identifier (ParamID) and some other data (&ParamX, SomeOtherDataX) associated with this parameter. All the available parameters are organized in a table, which is implemented as a struct array (ParameterList[]) in C. Thus, on each row I can see all associated data for one parameter. The following code snippet should (hopefully) make this clearer:
// predefined IDs; not changeable!
#define PARAM_ID_A 10
#define PARAM_ID_B 12
#define PARAM_ID_C 14
// the basic structure of my parameter list
typedef struct ParameterList_t {
int ParamID,
*int ParamAddr,
*float SomeConnectedData
}
// definition of my list in ROM
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_B, &Param2, SomeOtherData2},
{ PARAM_ID_C, &Param3, SomeOtherData3}
};
Now I want to create another list, which contains references on a subset of the parameters defined in the ParameterList[] table. This list should also be resided in ROM. I basically want to access all associated data for a subset of the parameters.
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[2], // parameter: PARAM_ID_B
&ParameterList[3], // parameter: PARAM_ID_C
};
The problem here is that the code will be maintained by many people and the parameter list (ParameterList[]) might change frequently and parameters will be sorted into the table at the beginning or in the middle. This means the sub list (ParameterSubListA[]) must be updated to point to the desired parameters if their index (index = row in ParameterList[]) changes.
Question:
Basically my code needs a mapping from ParamID to the index of the ParameterList[] table, preferably by use of the preprocessor and only in ROM. I found different ways to implement this, which are all not satisfying:
Option 1:
Automatically generate a list in the RAM at startup, which maps the ParamID to the index in ParameterList[]. What I get is an array, that could be called CrossRefTable[]:
IndexOfParameterA_InParameterList = CrossRefTable[PARAM_ID_A];
My sublist would then look like this (cannot be constant anymore :/ ):
*ParameterList_t ParameterSubListA[] = {
&ParameterList[CrossRefTable[PARAM_ID_B]], // parameter: PARAM_ID_B
&ParameterList[CrossRefTable[PARAM_ID_C]], // parameter: PARAM_ID_C
};
I am short of RAM, so I would prefer a solution that only uses ROM.
Option 2:
Use a predefined macro __COUNTER__, which increments with each call and generate a macro in each row:
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
#define PARAM_IDX_A __COUNTER__
{ PARAM_ID_B, &Param2, SomeOtherData2},
#define PARAM_IDX_B __COUNTER__
{ PARAM_ID_C, &Param3, SomeOtherData3}
#define PARAM_IDX_C __COUNTER__
};
My sublist would then look like this:
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_IDX_B], // parameter: PARAM_ID_B
&ParameterList[PARAM_IDX_C], // parameter: PARAM_ID_C
};
I would favorise this option, apparently it is not possible to use GCC.
Other Options:
I also figured there might be a possiblity in using X-MACROS, but I am not sure about that.
Boost is also not an option.
Hopefully my explanation is somehow clear...
Since the data is static, I'd say go on and initialize it statically.
Using external tools if the compiler is not capable enough.
parameter_list.c:
const struct ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_C, &Param2, SomeOtherData2},
{ PARAM_ID_B, &Param3, SomeOtherData3}
};
#include "parameter_list_index.h"
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_ID_C_INDEX],
&ParameterList[PARAM_ID_B_INDEX],
};
parameter_list.px:
#!/usr/bin/perl -n
print "#define $1_INDEX ".($n++)."\n" if
/^const.*ParameterList\[\]/../^}/ and /^\s*{\s*([^,]+)/;
Makefile:
parameter_list.o: parameter_list.c parameter_list.h
parameter_list_index.h: parameter_list.c
./parameter_list.px $< > $#
This is just a general idea, your implementation may differ of course.
You may choose to generate ParameterList[] the same way or use [PARAM_ID_A_INDEX] = { ... } to make extra sure the indexes match.
Note the code above relies heavily on formatting, which may or may not be ok.
And in any case, some people may find tricks like this inappropriate.
Were I doing this, and I needed flexibility
Then I would have defined an enum that matches the table of data.
(no actual instance of the enum needed, just the definition
Then declared an array that contains some values from the enum.
The values in that array are the offsets into the data array
I'm wondering if the following is possible:
I have a namespace-style struct setup, filled with just function pointers. These are provided in the header file like so:
typedef struct {
int32_t(*const event_construct)(struct sync_event* evt);
int32_t(*const event_destroy)(struct sync_event* evt);
int32_t(*const event_set)(struct sync_event* evt);
int32_t(*const event_wait)(struct sync_event* evt);
} namespace_sync;
extern namespace_sync const sync;
and then in the relevant source file, after all the function implementations:
...
namespace_sync const sync = {
sync_event_construct,
sync_event_destroy,
sync_event_set,
sync_event_wait
};
Say I want to add an extra function not at the end; I add it to the struct and source file, but forget to assign it. Because the function declarations match, a warning isn't generated for it, and the compiler (at least in this example, vs2013) doesn't provide a hint that there's an issue.
I've got compile-time assertion checks available, but not sure if I can verify this particular aspect, since the struct size is accurate. If vs2013 can't work with it - I'm aware it's an abysmal C compiler(!) - the newest versions of gcc will also be used, so I could limit the functionality to one compiler.
One solution going forward would be to use designated initializers:
namespace_sync const sync = {
.event_construct = sync_event_construct,
.event_destroy = sync_event_destroy,
.event_set = sync_event_set,
.event_wait = sync_event_wait
};
Any unlisted members will default to null pointers.
I would advise to not add members into the middle of a struct, because it is difficult to be sure that you have correctly updated any code that was relying on the old struct layout. However, if you really do want to do this, then one way to have the compiler indicate to you where all the uses of the struct are is to change the struct name:
typedef struct {
// ...
} namespace_sync_2;
Then the code namespace_sync const sync will cause a compilation error. This alerts you to the fact that this piece of code requires a code review to make sure that it will work correctly with the new struct layout.
I have to write code in C where the user has to have flexibility in choosing any existing DB, write to files, or implement their own storage mechanism. I need wrapper functions that redirect to the right functions corresponding to the storage mechanism selected at runtime or compile time. Say my storage options are FLATFILE and SQLDB and my wrapper function is insert(value). So, if I select FLATFILE as my storage, when I call the wrapper function insert(value), it should in turn call the function that writes to a file. If I choose a SQLDB, insert(value) should call the function that insert the values in the data base.
I know I can somehow use a structure of function pointers to do wrapper functions, but I have no idea how.
Does anyone know of any docs, links, examples, etc I could refer to, to understand and implement something like this? Any pointers will be appreciated. Thanks!
Thanks!
#define BACKEND_FLATFILE 0
#define BACKEND_SQLDB 1
void insert_flatfile(const t_value *v) {
...
}
void insert_sqldb(const t_value *v) {
...
}
void (*insert_functions[]) (const t_value *) = {
insert_flatfile,
insert_sqldb,
};
void insert_wrapper(t_value *v, int backend) {
insert_functions[backend](v);
}
Besides, the different functions for one backend should be stuffed into a struct and you should create an array of such structs instead of one array per wrapper function.
You can use a simple version such as:
struct backend {
int (*insert)(...);
int (*remove)(...);
...
};
static struct backend db_backend = { db_insert, db_remove, ... };
static struct backend other_backend = { other_insert, other_remove, ... };
const struct backend *get_backend(enum backend_type type)
{
switch (type)
{
case DB_BACKEND:
return &db_backend;
case DB_OTHER:
return &db_other;
...
}
}
All of the above can be hidden inside a C file, with get_backend and the enumeration being public. Then you can use it like this:
struct backend *b = get_backend(DB_BACKEND);
b->insert(...);
b->remove(...);
Many details are missing, of course (many people like using typedef, for example). This is a basic setup, you can also create wrapper functions if you don't like the b->insert(...) syntax or if you want to set the back end once and then use insert() and remove() in the code. This is also useful if you already have some code that calls insert() directly and you want to direct the call to the right back end.
If you want a more elaborate solution, have a look at http://www.cs.rit.edu/~ats/books/ooc.pdf. You don't have to implement every last detail from it, but it can give you a few ideas.