I'm trying to implement a framework, where I would need to declare (in .h file) the list of available "drivers" (struct variables) which would be defined in specific .c modules. As the list would probably grow in the future I would like to have it all in one place in the .h file to keep it easily extensible.
E.g. let's have "driver.h"
typedef struct driver {
int id;
char name[10];
int(*init)();
void (*deinit)();
int (*doTheJob)(int);
} driver_t;
#define DRIVERLIST driver1, driver2, driver3
#define DRIVERS extern driver_t DRIVERLIST;
DRIVERS
Then the specific drivers (driver1, driver2, driver3) would be defined in dedicated modules.. e.g. driver1.c, driver2.c .. etc...
But then I would like to have a module e.g. manager.c where I would like to define the array of available drivers as declared in driver.h so that I'm able to iterate the array and get the drivers for usage in other parts of the framework..
So in manager.c I would need something like:
driver_t drivers[MAX_DRIVERS] = {DRIVERS}
But obviously it does not compile this way..
The main idea is to edit only driver.h when I need to add declaration for additional driver in the future and then just implement it in dedicated module, whithout the necessity to edit e.g. manager.c or other parts of the framework..
Do you have any idea, how to implement such mechanism in c?
In C you can't initialize an array with copies of some objects (in C++ can but it is not good practice because they are copies and will be changed independently with original objects).
drivers array should contain pointers to original objects. I suggest something like
/* driver.h */
typedef struct driver {
int id;
char name[10];
int(*init)();
void (*deinit)();
int (*doTheJob)(int);
} driver_t;
#define MAX_DRIVERS 10
#define DRIVERLIST driver1, driver2, driver3
#define DRIVERS_INIT {&driver1, &driver2, &driver3}
#define DRIVERS extern driver_t DRIVERLIST;
DRIVERS
/* manager.c */
#include "driver.h"
/* ... */
driver_t * drivers[MAX_DRIVERS] = DRIVERS_INIT;
Manager code will use drivers[i]->id instead of drivers[i].id.
The proper way to do this in C is to immediately get rid of all extern-spaghetti with globals.
Instead you could put your struct definition inside driver.h and in driver.c initialize it through a "constructor":
// driver.c
#include "driver.h"
#include "specific_driver_x.h"
void driver_init (driver_t* driver)
{
driver->init = specific_driver_init;
driver->doTheJob = specific_driver_job;
}
For professional code, this can be further improved with the concept of "opaque type" as explained here, to achieve private encapsulation (and if needed polymorphism). In which case the struct definition can be (partially) hidden in driver.c and the constructor also handles memory allocation.
I think I found a solution. I took the inspiration from the rtl_433 project https://github.com/merbanan/rtl_433/blob/master/include/rtl_433_devices.h where they defined something similar for the devices declarations.
So it should be in header file:
/* driver.h */
#define DRIVERS \
DECL(driver1) \
DECL(driver2)
#define DECL(name) extern driver_t name;
DRIVERS
#undef DECL
And then in module:
/* driver.c */
driver_t* drivers[] = {
#define DECL(name) &name,
DRIVERS
#undef DECL
};
Related
I've been developing in C using eclipse as my IDE in my virtual machine with ubuntu, I've made some progress and I wanted to test them in the real product which is an embedded system using powerpc.
In order to compile that program for our product I use Code::Blocks in Windows but the compiler is a powerpc version of the gcc.
The same code is giving me an error in the powerpc version that doesn't appear in the ubuntu version.
I have two header files gral.h and module_hand.h as follows:
The gral.h file:
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
#include "module_hand.h"
typedef struct PROFILE
{
module_t mod; // this one comes from module_hand.h
int var1; // some other random variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */
The module_hand.h is defined as follows
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <stdint.h>
#include "gral.h"
typedef struct PROFILE profile_t;
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
int Mod_Init(profile_t *profile);
/* some other random functions */
#endif /* HEADERS_MODULE_HAND_H_*/
As you'll see, I don't use the PROFILE struct in the module struct, But I declare it forward to use it in the declaration of the Mod_Init function
This gives me a Error: redefinition of typedef 'profile_t'
and error: previous declaration of 'profile_t' was here
If I remove the forward declaration the error is Error: parse error before '*' token
where the line number is the line of the function declaration.
My doubt is what am I missing, and why gcc in Ubuntu does compile it with no problem.
Your powerpc compiler is enforcing the C99 rule that
If an identifier has no linkage, there shall be no more than one
declaration of the identifier (in a declarator or type specifier) with
the same scope and in the same name space, except for tags as
specified in 6.7.2.3.
(C99 6.7/3)
Your Linux compiler is observing the relaxed version of that rule that was introduced in C11:
If an identifier has no linkage, there shall be no more than one
declaration of the identifier (in a declarator or type specifier) with
the same scope and in the same name space, except that:
a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
tags may be redeclared as specified in 6.7.2.3.
(C11 6.7/3; also C17 6.7/3)
Supposing that the compilation options are the same, the behavior difference surely arises from using different versions of GCC. More recent versions default to more recent versions of the language.
You could try adding -std=gnu11 or -std=c11 to the command-line options (for both targets) to try to get consistency. If your powerpc version of GCC is too old to accept those then you really need to update to a newer version.
Note also, however, that you don't need to have this problem in the first place. Given that module_hand.h includes gral.h, the former has no need whatever to redefine a typedef that the latter already defines.
Moreover, the fact that these two headers each include the other is a strong suggestion that they ought to be combined into one. Multiple-inclusion guards prevent an actual loop, but they are not an adequate solution.
In the gral.h header file, you define profile_t using typedef, then you redefine profile_t with another typedef in module_hand.h. You should just define the struct PROFILE in gral_h and include gral.h in module_hand.h.
gral.h:
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
#include "module_hand.h"
typedef struct PROFILE {
module_t mod; // this one comes from module_hand.h
int var1; // some other random variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */:
module_hand.h:
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <stdint.h>
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
int Mod_Init(struct PROFILE *profile);
/* some other random functions */
#endif /* HEADERS_MODULE_HAND_H_*/
Well I read your answers and comments and decided to try another approach.
As some of you said, I had some kind of recursion, I wanted to keep every structure within its respective header file, but now, I dropped the idea and merged the structures in one file only.
My new approach:
Gral.h
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
typedef struct PROFILE {
module_t mod; // this one comes from module_hand.h
int var1; // some other variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */:
Module.h
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <Gral.h>
int Mod_Init(profile_t *profile);
/* some other functions */
#endif /* HEADERS_MODULE_HAND_H_*/
And when any other structure comes up, I'll declare it in Gral.h and include the header file.
Regarding the compilers, they aren't the same version. The powerpc is quite old now. That would explain the powerpc compilation errors.
Thank you again.
In my model I have quite some parameters that are used by a lot of different functions.
To make changing settings easy, I want to use one file for all my paramaters, keeping it sepperate from any of the "real programming".
That file is called parameters.c
In it, all parameters are defined like:
#define N 1000
#define T 1373
In a different c file (MyLib.c), I create a struct type:
typedef struct Model{
struct Element el[N];
};
both files are included in my main script using:
#include "parameters.c"
#include "MyLib.c"
The project can not be build this way. However, if I move the line
#define N 1000
from parameters.c to MyLib.c, it works.
I could just create the struct to have an array that is larger than any N value I'd use, but that doesn't seem like the correct way to do it.
Is there a correct way to implement this, or would I indeed have to create the large array? (in the comments it was said the definition of correct is too broad. In this instance I mean memory efficient. I don't want to allocate a much larger chunck of memory than I need to.)
Thanks in advance.
Is there a correct way to implement this
You library may look like this:
// parameters.h
#ifndef PARAMETERS_H_
#define PARAMETERS_H_
// documentation
#define PARAMETERS_COUNT_OF_ELEMENTS 1000
// this parameters does that and that
#define PARAMETERS_DESCRIPTIVE_NAME 1373
// ^^^^^^^^^^^ - consistent namespace naming
#endif
// mylib.h - safe yourself trouble and DoN'T mIx UppErCaSe with lOwErcAsE
// escapecially in header names
// subjectively, I do not like pascal case - snake case rule them all!
#ifndef MYLIB_H_
#define MYLIB_H_
#include "parameters.h"
#include "element.h" // for struct element
/// This structure represents a model in our library.
struct mylib_model {
// ^^^^^^ - consistent namespace naming
/// These are super important elements we deeply care about.
struct element el[PARAMETERS_COUNT_OF_ELEMENTS];
};
/**
* #brief this function does that and that
* #return 0 on success, otherwise error
*
* Write documentation keeping consistent style, for example
* use doxygen.
*/
int mylib_do_something(struct mylib_model *the_model);
#endif
// mylib.c
#include "mylib.h"
int mylib_do_something(struct mylib_model *t) {
// do something here
// return 0 on success, otherwise document error codes, or use the ones from errno.h
return 0;
}
// main.c
#include "mylib.h"
int main() {
struct mylib_model model = {0};
int err = mylib_do_something(&model);
if (err != 0) { abort(); }
return 0;
}
Your parmeters.h is very similar to the way autoconf projects generate config.h present in many GNU projects. Many projects use a configuration file, sometimes generate automatically by a build system. Nowadays if choosing build automation software I would recommend cmake. Other links: kernel coding style and google coding style.
I'm trying to minimize interdependence of #include files as a general practice.
In xxx.h I have:
struct my_struct; // partial decl to satisfy use of my_struct*
void funct(struct my_struct* ms); // uses the partial def
How to do a similar partial decl with a typedef'd struct?
I have an actual decl in some third #include that looks like (say in yyy.h):
typedef struct my_data_s {
int ival;
... struct's other components ...
} my_data_t;
I just want a representative decl in xxx.h that reference the typedef:
typedef struct my_data_s my_data_t; // actual full decl is elsewhere
void funct2(my_data_t* md);
This attempt causes 'redefinition of typedef my_data_t' error. (Using gcc 4.4.3 / Ubuntu 10.4) Other random search attempts (e.g., add '{}' to typedef) also give errors.
I know the compiler only needs to know that the function requires a pointer, so it seems like this should be possible. So far, found nothing that compiles w/o errors/warnings.
I've looked at the other questions and answers, could not find this problem addressed. Seems like there should be a well-known way to do this(?!) (I know that I can #include yyy.y whenever I #include xxx.h - trying to avoid such dependencies.) Thanks.
Have you tried the simple approach:?
xxx.h
struct my_data_s;
typedef struct my_data_s my_data_t;
yyy.h
#include "decl.h"
struct my_data_s {
int foo;
};
C99 doesn't allow to repeat a typedef, C11 does.
Just do the typedef only once and always have it first:
typedef struct my_data my_data;
There also is no need to chose different names for the struct tag and the typedef identifier.
Here's what our group decided to do. It represents a compromise of several conflicting requirements/desires. I am posting to show another approach, so readers of the post have some variety to choose from. It represents the best answer for our situation.
obj_a_defs.h
// contains the definition
// #include'd only by other .h files
...
#define ... // as needed for struct definition
...
typedef struct obj_a {
...
} obj_a;
obj_a.h
// contains the 'full info' about obj_a: data and behaviors
// #include'd by other .c files
...
#include "obj_a_defs.h"
...
// declares functions that implement
// the behaviors associated with obj_a
obj_a.c
...
#include "obj_a.h"
...
// implementations of functions declared in obj_a.h
obj_b.h
// a 'user' of obj_a that uses obj_a as arg
#include "obj_a_defs.h" // to get the typedef
...
int some_b_funct(obj_a* obja, ...);
...
obj_b.c
// Defines the 'contract' that this implementation
// is meeting.
#include "obj_b.h"
...
// This .c file includes obj_a.h only if it
// uses the functions defined for obj_a.
// If obj_a is used only to 'pass through'
// to other modules, there's no need for
// this include.
#include "obj_a.h" // only if obj_b uses
...
// obj_b's function implementations
Rationale / Conditions
typedef and struct kept together
a .c file that uses obj_X must #include "obj_X.h"
to show that use
avoid .h files including other .h files in general;
only 'defs.h' files are #include'd in .h files.
avoid #include'ing a file just to handle dependencies;
IOW avoid #include'ing obj_a.h just because it's used in obj_b.h
Having namespaces seems like no-brainer for most languages. But as far as I can tell, ANSI C doesn't support it. Why not? Any plans to include it in a future standard?
For completeness there are several ways to achieve the "benefits" you might get from namespaces, in C.
One of my favorite methods is using a structure to house a bunch of method pointers which are the interface to your library/etc..
You then use an extern instance of this structure which you initialize inside your library pointing to all your functions. This allows you to keep your names simple in your library without stepping on the clients namespace (other than the extern variable at global scope, 1 variable vs possibly hundreds of methods..)
There is some additional maintenance involved but I feel that it is minimal.
Here is an example:
/* interface.h */
struct library {
const int some_value;
void (*method1)(void);
void (*method2)(int);
/* ... */
};
extern const struct library Library;
/* end interface.h */
/* interface.c */
#include "interface.h"
void method1(void)
{
...
}
void method2(int arg)
{
...
}
const struct library Library = {
.method1 = method1,
.method2 = method2,
.some_value = 36
};
/* end interface.c */
/* client code */
#include "interface.h"
int main(void)
{
Library.method1();
Library.method2(5);
printf("%d\n", Library.some_value);
return 0;
}
/* end client code */
The use of . syntax creates a strong association over the classic Library_function(), Library_some_value method. There are some limitations however, for one you can't use macros as functions.
C does have namespaces. One for structure tags, and one for other types. Consider the following definition:
struct foo
{
int a;
};
typedef struct bar
{
int a;
} foo;
The first one has tag foo, and the later is made into type foo with a typedef. Still no name-clashing happens. This is because structure tags and types (built-in types and typedef'ed types) live in separate namespaces.
What C doesn't allow is to create new namespace by will. C was standardized before this was deemed important in a language, and adding namespaces would also threaten backwards-compatibility, because it requires name mangling to work right. I think this can be attributed due to technicalities, not philosophy.
EDIT:
JeremyP fortunately corrected me and mentioned the namespaces I missed. There are namespaces for labels and for struct/union members as well.
C has namespaces. The syntax is namespace_name. You can even nest them as in general_specific_name. And if you want to be able to access names without writing out the namespace name every time, include the relevant preprocessor macros in a header file, e.g.
#define myfunction mylib_myfunction
This is a lot cleaner than name mangling and the other atrocities certain languages commit to deliver namespaces.
Historically, C compilers don't mangle names (they do on Windows, but the mangling for the cdecl calling convention consists of only adding an underscore prefix).
This makes it easy to use C libraries from other languages (including assembler) and is one of the reasons why you often see extern "C" wrappers for C++ APIs.
just historical reasons. nobody thought of having something like a namespace at that time. Also they were really trying to keep the language simple. They may have it in the future
Not an answer, but not a comment. C doesn't provide a way to define namespace explicitly. It has variable scope. For example:
int i=10;
struct ex {
int i;
}
void foo() {
int i=0;
}
void bar() {
int i=5;
foo();
printf("my i=%d\n", i);
}
void foobar() {
foo();
bar();
printf("my i=%d\n", i);
}
You can use qualified names for variables and functions:
mylib.h
void mylib_init();
void mylib_sayhello();
The only difference from namespaces it that you cannot be using and cannot import from mylib.
ANSI C was invented before namespaces were.
Because people who want to add this capability to C have not gotten together and organized to put some pressure on compiler author teams and on ISO bodies.
C doesn't support namespaces like C++. The implementation of C++ namespaces mangle the names. The approach outlined below allows you to get the benefit of namespaces in C++ while having names that are not mangled. I realize that the nature of the question is why doesn't C support namespaces (and a trivial answer would be that it doesn't because it wasn't implemented :)). I just thought that it might help someone to see how I've implemented the functionality of templates and namespaces.
I wrote up a tutorial on how to get the advantage of namespaces and/or templates using C.
Namespaces and templates in C
Namespaces and templates in C (using Linked Lists)
For the basic namespace, one can simply prefix the namespace name as a convention.
namespace MY_OBJECT {
struct HANDLE;
HANDLE *init();
void destroy(HANDLE * & h);
void do_something(HANDLE *h, ... );
}
can be written as
struct MY_OBJECT_HANDLE;
struct MY_OBJECT_HANDLE *my_object_init();
void my_object_destroy( MY_OBJECT_HANDLE * & h );
void my_object_do_something(MY_OBJECT_HANDLE *h, ... );
A second approach that I have needed that uses the concept of namespacing and templates is to use the macro concatenation and include. For example, I can create a
template<T> T multiply<T>( T x, T y ) { return x*y }
using template files as follows
multiply-template.h
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y);
multiply-template.c
_multiply_type_ _multiply_(multiply)( _multiply_type_ x, _multiply_type_ y) {
return x*y;
}
We can now define int_multiply as follows. In this example, I'll create a int_multiply.h/.c file.
int_multiply.h
#ifndef _INT_MULTIPLY_H
#define _INT_MULTIPLY_H
#ifdef _multiply_
#undef _multiply_
#endif
#define _multiply_(NAME) int ## _ ## NAME
#ifdef _multiply_type_
#undef _multiply_type_
#endif
#define _multiply_type_ int
#include "multiply-template.h"
#endif
int_multiply.c
#include "int_multiply.h"
#include "multiply-template.c"
At the end of all of this, you will have a function and header file for.
int int_multiply( int x, int y ) { return x * y }
I created a much more detailed tutorial on the links provided which show how it works with linked lists. Hopefully this helps someone!
You can. Like other's answer, define function pointers in a struct.
However, declare it in your header file, mark it static const and initialize it with the corresponding functions.
With -O1 or higher it will be optimized as normal function calls
eg:
void myfunc(void);
static const struct {
void(*myfunc)(void);
} mylib = {
.myfunc = myfunc
};
Take advantage of the #include statement so you do not need to define all functions in one single header.
Do not add header guards as you are including it more than once.
eg:
header1.h
#ifdef LIB_FUNC_DECL
void func1(void);
#elif defined(LIB_STRUCT_DECL)
struct {
void(*func)(void);
} submodule1;
#else
.submodule1.func = func1,
#endif
mylib.h
#define LIB_FUNC_DECL
#include "header1.h"
#undef LIB_FUNC_DECL
#define LIB_STRUCT_DECL
static const struct {
#include "header1.h"
#undef LIB_STRUCT_DECL
} mylib = {
#include "header1.h"
};
I'm just getting started with modular programming in C. I think I'm doing something wrong with the inclusions, because I'm getting a lot of conflicting types for 'functionName' and previous declaration of 'functionName' was here errors. I did put inclusion guards in place.
Do you know a clear tutorial that explains modular programming in C, especially how the inclusions work?
Update: I have tried to isolate my issue. Here's some code, as requested.
Update 2: updated code is below. The errors have been updated, too.
/*
* main.c
*/
#include <stdio.h>
#include "aStruct.h"
int main() {
aStruct asTest = createStruct();
return 0;
}
/*
* aStruct.h
*/
#ifndef ASTRUCT_H_
#define ASTRUCT_H_
struct aStruct {
int value1;
int value2;
struct smallerStruct ssTest;
};
typedef struct aStruct aStruct;
aStruct createStruct();
#endif /* ASTRUCT_H_ */
/*
* smallerStruct.h
*/
#ifndef SMALLERSTRUCT_H_
#define SMALLERSTRUCT_H_
struct smallerStruct {
int value3;
};
typedef struct smallerStruct smallerStruct;
smallerStruct createSmallerStruct();
#endif /* SMALLERSTRUCT_H_ */
/*
* aStruct.c
*/
#include <stdio.h>
#include "smallerStruct.h"
#include "aStruct.h"
aStruct createStruct() {
aStruct asOutput;
printf("This makes sure that this code depends on stdio.h, just to make sure I know where the inclusion directive should go (main.c or aStruct.c).\n");
asOutput.value1 = 5;
asOutput.value2 = 5;
asOutput.ssTest = createSmallerStruct();
return asOutput;
}
/*
* smallerStruct.c
*/
#include <stdio.h>
#include "smallerStruct.h"
smallerStruct createSmallerStruct() {
smallerStruct ssOutput;
ssOutput.value3 = 41;
return ssOutput;
}
This generates the following error messages:
At aStruct.h:10
field 'ssTest' has incomplete type
At main.c:8
unused variable `asTest' (this one makes sense)
The base of inclusion is to make sure that your headers are included only once. This is usually performed with a sequence like this one:
/* header.h */
#ifndef header_h_
#define header_h_
/* Your code here ... */
#endif /* header_h_ */
The second point is to take care of possible name conflicts by handling manually pseudo namespaces with prefixes.
Then put in your headers only function declarations of public API. This may imply to add typedefs and enums. Avoid as much as possible to include constant and variable declarations: prefer accessor functions.
Another rule is to never include .c files, only .h. This is the very point of modularity: a given module dependant of another module needs only to know its interface, not its implementation.
A for your specific problem, aStruct.h uses struct smallerStruct but knows nothing about it, in particular its size for being able to allocate an aStruct variable. aStruct.h needs to include smallerStruct.h. Including smallerStruct.h before aStruct.h in main.c doesn't solve the issue when compiling aStruct.c.
The multiple definition problem is most likely coming from the way you're including the code. You are using #include "aStruct.c" as opposed to #include "aStruct.h". I suspect you are also compiling the .c files into your project in addition to the #include. This causes the compiler to become confused due to the multiple definitions of the same function.
If you change the #include to #include "aStruct.h" and make sure the three source files are compiled and linked together, the error should go away.
Such errors mean that function declaration (return type or parameter count/types) differs from other function declarations or function definition.
previous declaration message points you to the conflicting declaration.