Design for program C

Good / Right Way to Do It for a Reliable C Program

//File1 => Module1.h static int Fun(int); struct{ int (*pFn)(int) }Interface; 

// File2 => Module1.c

 static int Fun(int){ //do something } Interface* Init(void) { Interface *pInterface = malloc(sizeof(Interface)); pInterface->pFn = Fun; return pInterface; } //File 3 => Module2.c #include"Module1.h" main() { Interface *pInterface1 = Init(); pInterface1->pFn(5); } 

My intention is for each module to expose an interface ...

Questions:

  • Is it good to write C code as shown above to open the interface ... ??
  • What more accessible methods are available for displaying the interface?
  • Are there any references to design principles for programming in C (and not in C ++)?
+7
c design
source share
3 answers

This is more idiomatic for a dynamically loadable module. (Or something like that.)

Typically, the interface between two source files is defined using extern functions and objects that are accessed directly. You will need to do business for something more complex.

+1
source share
  • If you use it to solve a simple task, this can only increase the base code and complexity. But in some places this may be useful.
    For example: if you want to implement STRATEGY-pattern in C, then there is one way to do this.
  • You can hide the contents of the Interface structure from users using the FIRST-CLASS ADT pattern . Or you can combine the above patterns.
0
source share

My short answer is no.

Ignoring comments indicating that a static function should not be declared in the .h file (this is the part you want to hide), it's still static), here are some things to keep in mind.

It seems that you are trying to use the interface to cancel the implementation from consumers of the module; noble goal. This can provide more flexibility, since the implementation can be changed in the .c file without breaking the call code. However, think about the interface you defined.

Any code using this module must be guaranteed to receive an instance of the interface through Init (although this should be included in your .h file). This instance of the interface will indicate the functions that will be used. One such function has a signature

 int Fun(int); 

So what did you hide? Of course, you can change the function that they call, but you still need to provide a function with this signature.

Alternatively, you can simply define .h as:

 int Fun(int); 

And then in the .c file, something like:

 static int StaticFun(int i) { // something } int Fun(int i) { StaticFun(i); } 

You can make a fun call another function based on some internal state that it controls, or a configuration file, no matter what you want. Why is it better? Besides simplicity, this is a static call; for example, the compiler may include a call to StaticFun or even a function called StaticFun. Calls through function pointers usually cause a noticeable performance hit.

Now there may be a case for an Interface object, for example, that you defined. But I would be inclined to assume that in your case there is nobody, not without changes.

Suppose your Init function has changed to:

 Interface* Init(some state info); 

Now, the interface object that you pass back can change depending on the state or configuration passed to, which allows your module to dynamically display functions. Basically, I believe that if you actually call a static function at the bottom, then you are working a lot harder than necessary, and you prevent the compiler from being optimized.

As a note, if you are going to follow the interface (I'm currently working on a project with something similar), can I suggest a modification? Something like...

.h file:

 const Interface* Init(some state); 

.c file:

 static int FunTyp1(int); static int FunTyp2(int); static const Interface typ1 = { &FunTyp1 }; static const Interface typ2 = { &FunTyp2 }; const Interface* Init(some state) { if (some state == type1) return &typ1; else if (some state == type2) return &typ2; } 

Benefits:

  • You probably don't want the consumer code modifying the interface? At least I can't think of a good reason.
  • By defining this, it statically avoids unnecessary heap allocation and memory leaks when consumers re-request Interface objects and forget to free them (or don’t know what they need - who owns this object?).
  • You can share one (static) instance of the Interface object for the entire consumption code in the process without worrying about someone changing it.

Note that with several statically initialized instances, you can define a different Interface object for each function mapping you want to support.

0
source share

All Articles