function inside struct in c

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

I practice in OOP in C. And I have difficulties to apply the function inside  struct in the language c.
Here is for example a  c++ code that I try to rewrite in language c.
Please can anyone tell me what is incorrect in this transcript?
Thank you in advance

 

class cp  
{
public:
            void Encode();
            int  Data(int * p);
private:
            void Gf();
            int m, n;    
};

 

void cp::Encode()
{   
    
    m = 5; n = 31;  // initialisierung
    m += n-7;

void cp::Data(int *p)
{
    for (int i=0; i<21; i++)
        m[i]=p[i];
}

int cp::calculate()
{
     cp m_cp;
     int tmp, tmp2 ;
     tmp2 = m_cp.Encode(tmp);
     m_cp.data(tmp);

}

 

I have implemented as follows in c code.

typedef struct cp
{
        int m,n,d[31];
        void (*cp_Encode)();
        int  (* cp_Data)(int * p);
    void (* cp_Gf)();
}cp;

cp m_cp;         // as globale variable

void Encode()
{   
    
    m_cp.m = 5; m_cp.n = 31;         // init variable 
    m_cp.m += m_cp.n-7;

void Data(int *p)
{
    for (int i=0; i<21; i++)
        m_cp.d[i] = p[i];
}

int calculate()
{
     
     int tmp, tmp2 ;
     m_cp.cpEncode = Encode;
     m_cp.cpData = Data;

     tmp2 = m_cp.cpEncode();
     m_cp.cpdata(tmp);

}

greeting 

Etie

Last Edited: Thu. Dec 15, 2016 - 05:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is kind of the whole reason of moving from C to C++ in the first place. In C a struct is used to group together some associated data. In C++ a struct or class is used to group together not only that data but also all the functions that make use of it. So why are you bothering to go "backwards"? Surely it's best to just use C++ all the time if you understand it?

 

Anyway in your C++ example you have:

void cp::Data(int *p)
{
    for (int i=0; i<21; i++)
        m[i]=p[i];
}

that makes no sense whatsoever when you have:

private:
            int m, n;    

How on earth can you use [i] subscripted indexing on the member called 'm'? It is not a pointer!

 

Also your C++ has:

int cp::calculate()
{
     cp m_cp;
     int tmp, tmp2 ;
     tmp2 = m_cp.Encode(tmp);
     m_cp.data(tmp);

}

but that is referring to m_cp  which is the replacement struct variable in your later C code translation?

 

Also your C++ does this:

     tmp2 = m_cp.Encode(tmp);

that is calling an Encode method as it it wlil have some return value. Yet the function is implemented as:

void cp::Encode()
{  

This is all very confused!

 

As the C++ makes no sense whatsoever you don't stand any hope of converting it to C.

 

But anyway the general technique if you were trying to ruin the simplicity of C++ by trying to implement half-baked C would be to write functions that took a pointer to the struct instance as a parameter then work on the struct data in the functions using that pointer. If you think about it that is EXACTLY what "this" provides when you are writing C++!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you spontaneous reaction

 

I'm sorry about the content of this program.
My worry is to understand the technique of using OOP in C.
I just sketched a code because it is very large.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so here is what I think is a clean example of converting some C++ back to C. First the C++:

#include <avr/io.h>

class Foo {
public:
    void setData(int n);
    int getIncrementedData();
private:
    int m_n;
};

void Foo::setData(int n) {
    m_n = n;
}

int Foo::getIncrementedData() {
    m_n++;
    return m_n;
}

int main(void) {
    Foo myFoo;

    myFoo.setData(37);
    PORTB  = myFoo.getIncrementedData();
    PORTB  = myFoo.getIncrementedData();
    PORTB  = myFoo.getIncrementedData();

    return 0;
}

That is going to write 38,39,40 in turn to PORTB. Here is my C version of the same:

#include <avr/io.h>

typedef struct {
    int n;
} Foo_t;

void setData(Foo_t * pStruct, int n) {
    pStruct->n = n;
}

int getIncrementedData(Foo_t * pStruct) {
    pStruct->n++;
    return pStruct->n;
}

int main(void) {
    Foo_t myStruct;

    setData(&myStruct, 37);
    PORTB  = getIncrementedData(&myStruct);
    PORTB  = getIncrementedData(&myStruct);
    PORTB  = getIncrementedData(&myStruct);

    return 0;
}

As you can see there is now nothing to specifically bind the functions and data together except that I have specified that each function that acts on the data gets a pointer to the structure when it is invoked. Unlike C++ it now becomes the programmer's responsibility to ensure that the pointer to an instance of struct data is passed to the functions that act on the data (this happens in C++ too but it is invisible as all member functions have a "hidden" first parameter called "this" which is a pointer to the block of data for the instance of the class.

 

Still don't understand why you would want to destroy the simplicity of the C++ to revert to doing it in C but if you were going to then doing pretty much what C++ does anyway (passing a pointer to instance data) would be the way to achieve it. As the member functions don't have any direct connection to the data they operate on you might want to invent some kind of naming scheme too that would indicate that setData() and getIncrementedData() were only really for operating on data of type Foo_t. So perhaps:

void Foo_setData(Foo_t * pStruct, int n) {
    pStruct->n = n;
}

int Foo_getIncrementedData(Foo_t * pStruct) {
    pStruct->n++;
    return pStruct->n;
}

which is about as close as you will get to "Foo::setData(" etc. Or maybe the fact that the very first parameter to each is a struct pointer already identifies that these functions are in the same "class" as the Foo_t data they operate on?

 

But why not just stick with C++ ?!?!?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much for the effort and time provided
to help me.

thanks again

Etie

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

www.embedded.com had an article on just this:

http://www.embedded.com/electronics-blogs/other/4024626/Object-Oriented-C-Creating-Foundation-Classes-Part-1

Transforming a structured language into an object-oriented language may cause some pain at first. However, the benefits of rapid behavioral changes far exceed any early discomfort.

I read it with interest but decided the "early discomfort" was excessive and the technique detracted readability too much; so it wasn't for me.

 

clawson wrote:
But why not just stick with C++ ?!?!?

Surely down to the lack of a good c++ library for AVR wouldn't we be writing mostly C anyway.

{ I hope to stand corrected on this }

 

Last Edited: Thu. Dec 15, 2016 - 01:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Rather that suffer the discomfort in "transforming" C into something it wasn't designed for, wouldn't it be better to take the "discomfort" in learning C++ properly ... ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

N.Winterbottom wrote:
Surely down to the lack of a good c++ library for AVR
Do you mean a lack of STL or something else? There are implementations of STL for AVR from 3rd parties. Or did you mean peripheral drivers? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suppose I should first ask myself where does C let me down & c++ would help.

 

Immediate thoughts are:

  1. Exceptions: The passing around and checking of return codes which invades much of my C code. I would like to read (and of course write) code that concentrates on the path of success and let exceptions handle the nastiness.
  2. Dynamic memory management: For example, I need to preserve variables across adjacent states of a state machine, so allocate static storage. It is essentially unused (so wasted memory) thereafter. Worse still I come under SRAM pressure and start reusing these blocks of memory for other purposes by casting pointers {reinterpret_cast} onto these blocks and create bugs by subsequently writing over the end of the block.
  3. enum type safety: That's bitten me from time to time.
  4. Data encapsulation and abstraction: Or something to help decrease module coupling. Many of my C modules {A ha! what's a module in C ?} depend on pretty much 66% of the rest of the project, the majority being global variables. This is a major hindrance to code re-use.

 

I suppose one way to start is simply to recompile an existing C project using the c++ compiler and see just how far I get.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you absolutely must use functions in a struct;

 

struct someStruct
{
        int someInt;
        
        int (*foo)(int param);    
};

int foo(int param)
{
    //Code goes here
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike, 

 

But that isn't putting the function in the structure? All that is doing is putting a 16 bit function pointer placeholder which at the point of instantiation would still need to be set to point at foo(). 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Mike, 

 

But that isn't putting the function in the structure? All that is doing is putting a 16 bit function pointer placeholder which at the point of instantiation would still need to be set to point at foo(). 

 

Very true, it would have to be set just like other variables in the struct, also it's not a very elegant solution.

I've been espousing the benefits of C++ on AVR for a long time now and there's no reason that it can't be implemented on most AVR chips.  There are exceptions of course!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
But that isn't putting the function in the structure? All that is doing is putting a 16 bit function pointer placeholder which at the point of instantiation would still need to be set to point at foo().

I guess:  So what?  If you make "good" C++ code, won't it be the same storage and cycles as C-equivalent of "instantiation"?  And if you use full-blown C++ then aren't you subject to possible bloat that makes it impractical for AVR8?

 

[In practice, I rarely use function pointers in my AVR8 apps.  I was going to say 1 out of 10 or less, but I do have a number of Modbus RTU apps that use a couple call-back functions depending on the protocol state.  But the function pointer table is fixed at build time.  What about y'all?  Do you regularly use function pointers in your AVR8 apps?]

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No I don't and then main reason is that GCC make some bad code.

I would like to use it so ISR's ran a special function depending of state.

(So for a fast a simple solution I use ASM with IJMP )

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"Do you regularly use function pointers in your AVR8 apps?" - Only if Atmel forces me to (they seem to like them and use extensively (in the QTouch library, for example)).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Do you regularly use function pointers in your AVR8 apps

Yep. Big Time.

 

  1. I prefer a table driven approach to many coding problems. So in command processors I have a large const table of strings and function pointers to handle each command. No huge if , else if chains then.
  2. My mainloop calls many a small dispatcher function in each module which in turn calls a function pointer to handle the next stage of processing. I can set it to NULL to deactivate the task also.
  3. LCD update handling is probably where c++ would help, as exemplified in the embedded.com link I posted above. A function pointer is set to a particular update function depending on what is currently being displayed.

 

 

Last Edited: Thu. Dec 15, 2016 - 10:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your 1:

 No huge if , else if 

most people would make a switch in this case.  

 

Your 3:

I can't see why c++ would be better than the way you do it in 1. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

I guess:  So what? 

well for me it's more about the simplicity and elegance of the code than anything else. There is little doubt that C++ just looks more elegant than C and hence is more readable/maintainable. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
most people would make a switch in this case.

Not when doing string compares they don't. Well string.startswith() to be exact. (Ooh that would need Python, Java or .net then wink)

 

Actually there was a recent rambling thread about something similar recently ... time passes ... ... Here it is:

http://www.avrfreaks.net/forum/faster-code

 

Regarding No3. That's the way OO GUI elements work. Look at Qt if you want a c++ example.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm with clawson, not only for the simplicity and elegance aspects but modularity and reusability among other features of the language.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Etie wrote:
My worry is to understand the technique of using OOP in C.

OOP is indeed a programming technique and is largely independent of the language you use.

 

If you want to do OOP in C you can think of each source code file as being an object / class.

Any variables (or functions) declared with the keyword "static" wil be confined to that source code file only.

If you do not declare your data or funtions as static and add "extern" to the prototype's in the header then you basically have made a public variable or function which is visible and usable from each source file where the header is included.

 

OOP is a great technique but it does take some effort to get used to. Especially if you're just starting with programming.

I started about 30 years ago ( Feeling old now) in C and  I've added some light C++ syntax sugar around my old C libraries recently as a practice in OOP and C++.

When I started programming, using more than one source file was a pain in the butt, but it also forced me to think about code structure and to make clean barriers between different parts of the code. And in the end it made the transformation from C to C++ almost trivial. Also, I had some loose ends in the C library which just fell into place when "upgrading" to C++.

 

In the most extreme form of OOP everything becomes an object. Even something such as an integer, which used to be nothing more than a number.

I've been experimenting a bit with this where an int was "smart enough" to read itself from a file or print to the monitor in a special format.

That experiment still feels weird, even though it was several years ago.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

Last Edited: Fri. Dec 16, 2016 - 02:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:
In the most extreme form of OOP everything becomes an object. Even something such as an integer, which used to be nothing more than a number. I've been experimenting a bit with this where an int was "smart enough" to read itself from a file or print to the monitor in a special format. That experiment still feels weird, even though it was several years ago.

 

Check out serialize/deserialize in C#.