AVR C++ (cpp)

Go To Last Post
73 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I 'was looking around the forum for something similiar, but it seems that the search engine is ommiting the "plus plus" so it's getting difficult to look for info about this.

I've been developing apps in C with WinAVR, and now I will like to do it in C++ in order to use things like polymorphism, virtual functions, classes, objects...

How can I find a guide or tutorial to look what things can be done with WinAVR in C++ and what things doesn't.

I guess that Exceptions are not supporting, but I don't need them. I need class heritage and virtual funtions.

Thanks

Ezequiel

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

ezequiel.aceto wrote:
and now I will like to do it in C++ in order to use things like polymorphism, virtual functions, classes, objects...
IMHO C++ on a small AVR is nor worth it. If you program in C++ as if it is C you won't need much additional memory, if at all. But if you start to use the pearls of C++ you'll have to pay with memory.

Anyhow, see:

https://www.avrfreaks.net/index.p...

http://www.nongnu.org/avr-libc/u...

Stealing Proteus doesn't make you an engineer.

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

Check the sticky thread "avr-c++ micro how-to".

Quote:
IMHO C++ on a small AVR is nor worth it.

This is a very subjective opinion and one that has been hashed over many times on these forums. The bottom line is: if you want to use C++, go ahead and use it. There are some things that you have to be aware of, however. The support for C++ on the AVR is incomplete (the things that you need to do to get it to work are described in the thread I mentioned above). There are some aspects of C++ that you probably to not want to use on an AVR (virtual functions, for instance, could be problematic).

Regards,
Steve A.

The Board helps those that help themselves.

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

I see... I'm using ATMega644, and would like to use a bigger one in the future. I'm developening a graphical UI. So I wanted to use C++ in order to use things like class heritage, which is very useful when drawing UI at high level.

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

ezequiel.aceto wrote:
I see... I'm using ATMega644, and would like to use a bigger one in the future. I'm developening a graphical UI. So I wanted to use C++ in order to use things like class heritage, which is very useful when drawing UI at high level.

If you don't want to tackle C++, but you're up for a challenge, you can still use an object-oriented design in C. Using function pointers - maybe a little "creative" typecasting - and you're doing the same thing C++ does but without needing to be an expert in the details of C++ compilation.

(I'm pretty sure this will work on an AVR, someone will correct me if I'm wrong =)

This code won't compile, but gets the idea across. It's useful if all of the "classes" share the exact same data. Things get trickier if different derived classes need totally different local storage, but that can be handled in other C-style ways. I wouldn't try to do anything much more complicated, as it gets a little hairy to debug, even with a debugger.

typedef void (*DrawFuncPtr)(GUIobj_t *pObj);

typedef enum
{
   GUIType_Button,
   GUIType_Text
} eGUITypes;

typedef struct 
{
   eGUIType     GUIType;
   DrawFuncPtr  DrawFunc;
} GUIobj_t;

void CreateObj(GUIobj_t  *pObj, eGUITypes  ObjType)
{
   // pObj assumed to already be allocated

   switch(ObjType)
   {
   case GUIType_Button:
       pObj->GUIType = GUIType_Button;
       pObj->DrawFunc = &DrawFunc_Button;
       break;

   case GUIType_Text:
       pObj->GUIType = GUIType_Text;
       pObj->DrawFunc = &DrawFunc_Text;
       break;
   }
}

void Draw(GUIobj_t  *pObj)
{
   (pObj->DrawFunc)(pObj);
}

void DrawFunc_Button(GUIobj_t  *pObj)
{
  //code to draw a button object here
}

void DrawFunc_Text(GUIobj_t  *pObj)
{
  //code to draw a text object here
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
This is a very subjective opinion
No, it is not subjective. If you don't use the advantages of C++, or like you wrote it
Koshchi wrote:
There are some aspects of C++ that you probably to not want to use on an AVR (virtual functions, for instance, could be problematic).
you are just using C++ as a glorified C. So what is then the point of using C++? Just so you can claim it has been done in C++?

Honest C code is much to be preferred over C code coming in C++ drag.

Stealing Proteus doesn't make you an engineer.

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

Here we go again...

I'd like the ability to think in objects doing actions, eg o.a() rather than having functions operate on data, eg f(d).

I'd like to use inheritance.

Could you give me a rough sketch of the cost of using these techniques, Arnold?

Could you explain how using these C++ features, but not all other C++ features, makes the code be "glorified C in drag"? Do I have to use pure virtual functions, templates and operator overloading in every C++ program I write in order to avoid this branding?

Arnold wrote:

IMHO C++ on a small AVR is nor worth it.

OP wrote:

I'm using ATMega644, and would like to use a bigger one in the future.

64K flash is 32K instructions. Assuming 10 instructions per LOC would give 3.2 dense KLOCs. I've written applications smaller than that (in KLOCs) where C++ was warranted IMO.

Here's my opinions based on facts:

Calling a non-virtual member function in C++ costs no more than calling a function in C. Every member function in C++ gets passed the this-pointer, but OTOH any C function that operates on data would need that data (or a pointer to it) passed as a parameter, or would work on global data. In the latter case, just use a static function for C++. Bottom line: Encapsulation is resolved at build time and costs you nothing, or very close to nothing.

Calling an inherited (non-virtual) member function has all the same properties as above, is resolved at build time and costs you no more.

Virtual functions, by their very nature, must be resolved at run time. This involves one or two indirections (this pointer points to V-table that points to virtual functions). There is a definitive cost, both in time and space to use virtual functions. I have no definitive figures though. Before anyone claims that C++ on an AVR is expensive in this respect I'd like to see i) a definition of "expensive" and ii) some actual figures (what is the space cost for the V-table, what is the time cost for a call?). And I see here at 'freaks from time to time plans on using a table of function pointers in C. Why do I not see the same arm-waving, jumping up and down, and yelling "no-no, that is too expensive!" in those cases.

We are now left with costs for things like startup, object construction etc.. Do we have a list of the these things? (AFAIK, no). Do we know their costs? (Again AFAIK, no). Does that stop people from claiming that it costs to much? (Obviously no.)

Get the facts and numbers on the table and then we can have a productive discussion.

You have to know what C++ "does behind the scenes" in order to use it effectively. That holds for C++ on any platform. But that also goes for using C, so..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Tue. Oct 7, 2008 - 11:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess the C versus C++ thing will go on forever. All I know is I'd give up programming before I'd go back to C.

I tried virtual functions once and found a HUGE HUGE HUGE increase in RAM and ROM usage. Feel free to try virtual functions but I suggest you keep an eye on memory usage.

As far as I know everything else in C++ works except exceptions.

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

If nothing else C++ is at least one of the most successful marketing ploys of all time.

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

I did not say don't use any aspects of C++, I said you may not want to use some aspects of C++. There are plenty more that are both useful and viable on the AVR.

Regards,
Steve A.

The Board helps those that help themselves.

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

ArnoldB wrote:
just using C++ as a glorified C. So what is then the point of using C++?
Included with the glory are some useful but non-OO features; these can make life easier for the programmer. For example, default parameters and operator overloading.

As previously noted, care should taken when applying virtual functions. Add to that: templates. These features can certainly be used, but resource scarcity on a microcontroller requires extra attention.

C: i = "told you so";

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

JohanEkdahl wrote:
Get the facts and numbers on the table and then we can have a productive discussion.
Here's some numbers and assembly listings that I generated from the another time when there was a discussion of the costs of C++: http://www.avrcode.com/serial_lcd/

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

ArnoldB wrote:
So what is then the point of using C++? Just so you can claim it has been done in C++?

C++ is a better language and can have a better compiler that can produce more efficient code, but that depends on the particular compiler.

C++ classes are enough reason to use C++. Classes give you modularity and scope and make understanding and reusing code easier.

In C, scope is file scope or compilation unit scope. Looking back at that, it seems childish. :)

Class constructors are a good thing also. Almost every module needs some initialization and that's what the constructor is for. When I look at C code I see things like ADC_init(). That begs the question of where and when it's called. With C++ there are no questions. The constructor is called when the class is constructed.

C programmers say they can write modular code, but it's easier to write and easier to read with C++. The C++ compiler will help you and remind you when you go astray. If you want to access something in another class you must scope it with the scoping operator. That makes it obvious for all to see, and also avoids name pollution.

The compilers I used when I was still using C were not as smart and industrious as the C++ compilers, but I suppose they might have gotten better in the interim. The C++ compilers check more things for the programmer than the C compilers I knew.

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

This is trivial I suppose, but I am made aware of it constantly. Here's an enum:

enum   {
   a,
   b,
   c,
   };

Note the comma after the last member. That is legal in C++ so I always put a comma after each member. As I develop, enhance, or re-use classes, I am constantly adding, deleting, or moving around the enum members. As long as I have a comma following each member, it's easy. If I should fail to put a comma after the last one, then when I re-arrange things, as sure as night follows day, the compiler will yell at me.

Well, maybe that's legal in C also. But enums seem to be used more in C++, and I think that's because of their scope.

I wish the same rule applied to function arguments, but alas it does not. The rule here is all arguments must have a trailing comma except the last one which must not have a trailing comma. Picky, picky, picky. When I run afoul of that rule, it reminds me of the children's game Simon Says. Does everyone know the game where you are told "you lose, I didn't say "Simon says"! :)

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

steve17 wrote:
Well, maybe that's legal in C also.
It is.

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

JohanEkdahl wrote:
And I see here at 'freaks from time to time plans on using a table of function pointers in C. Why do I not see the same arm-waving, jumping up and down, and yelling "no-no, that is too expensive!" in those cases.

Because in almost all situations that arrays of function pointers are used, they are constant and stored in program memory, generaly a far more available resouce than RAM on small micros. All linking in this case is performed at compile time, so the overhead of using a const array of function pointers is minimal.

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

steve17 wrote:

C++ is a better language

For some values of 'better' ;)

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

MikeRJ wrote:
JohanEkdahl wrote:
And I see here at 'freaks from time to time plans on using a table of function pointers in C. Why do I not see the same arm-waving, jumping up and down, and yelling "no-no, that is too expensive!" in those cases.

Because in almost all situations that arrays of function pointers are used, they are constant and stored in program memory, generaly a far more available resouce than RAM on small micros. All linking in this case is performed at compile time, so the overhead of using a const array of function pointers is minimal.

Got it. Good answer.

(I now have to investigate wether avr-gcc will place a V-table in FLASH or RAM. From your answer I suspect and fear that avr-gcc will place it in RAM. This is not far fetched as the tweak of the compiler to i) place the V-table in FLASH, and ii) do the "virtual lookup" through FLASH, might be non-trivial.)

Or half-got it, actually. If the function pointer array is used like you describe then it is not the C counterpart to virtual functions. So I was in error when comparing these two. (The investigation of where the V-table ends up is still interesting though.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

ezequiel.aceto wrote:
I 'was looking around the forum for something similiar, but it seems that the search engine is ommiting the "plus plus" so it's getting difficult to look for info about this.

You are using the wrong search engine.

Do a google search of this:
C++ site:avrfreaks.net

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

steve17 wrote:

C++ is a better language and can have a better compiler that can produce more efficient code, but that depends on the particular compiler.

I find it hard to believe a compiler should produce more efficient code with C++. On the contrary, I'd expect.
Have any links?

Quote:
C++ classes are enough reason to use C++. Classes give you modularity and scope and make understanding and reusing code easier.

Bull, it perhaps makes it a little easier, but all this is fully possible in C.
And code reuse, is still a dream, I haven't seen ANY advantages in real life with C++ in that respect. I hardly see any code reuse at all, actually, apart from more common copy/paste.

Quote:
In C, scope is file scope or compilation unit scope. Looking back at that, it seems childish. :)
extern vs. public ?

Quote:
Class constructors are a good thing also. Almost every module needs some initialization and that's what the constructor is for. When I look at C code I see things like ADC_init(). That begs the question of where and when it's called. With C++ there are no questions. The constructor is called when the class is constructed.
ADC_init is called where it says ADC_init() in the code. No different from the constructor.
Actually, if the constructor did the initialization, you could only have one object instance (unless protecting the initialization with a static member flag).

Quote:
C programmers say they can write modular code, but it's easier to write and easier to read with C++.

That's probably true if you know C++ well, otherwise it can get VERY weird. The opposite is just as true.

Quote:
The compilers I used when I was still using C were not as smart and industrious as the C++ compilers, but I suppose they might have gotten better in the interim. The C++ compilers check more things for the programmer than the C compilers I knew.

C++ is a much more "safe" language in that respect. To the extent that you're about to go nuts over warnings for simple "shortcuts".

I really don't think C++ has much use in small micros such as AVR's where it's a huge amount of hardware related code. For the application part, it's another story.
I'd think another problem is when people that has been thought C++, enter the AVR world and think then can continue programming as if they have 3GB of memory available.
But that's not the fault of the language.

If you have grown up with C and know the limitations of C++ when used close to hardware in a small memory footprint environment, then perhaps it has it's use.
For some, not for me.

/Jesper
http://www.yampp.com
The quick black AVR jumped over the lazy PIC.
What boots up, must come down.

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

steve17 wrote:
C++ is a better language and can have a better compiler that can produce more efficient code, but that depends on the particular compiler.

Efficient in what respect?

jesper wrote:

Bull, it perhaps makes it a little easier, but all this is fully possible in C.

With that kind of arguing C can be dismissed too. All we need is assembler. Oh, sorry, all we need is a front panel with ADDRESS and DATA switches, and a LOAD button.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

jesper wrote:
I find it hard to believe a compiler should produce more efficient code with C++. On the contrary, I'd expect.
Have any links?

Well I probably shouldn't have mentioned it because I don't see it as an important reason to use C++. But I do think the compiler would have an easier time of it with C++ code.

Inline functions can produce more efficient code and they are usually easier to implement with C++. You can just put the functions n the class definition so they can be used from any other module that includes the header. There might be a way to do this in C but I don't know how and I doubt most people do.

The relationship of private class members to the rest of the program is obvious to the compiler because there is none. You might be able to do this in C with statics but it's easier to write and read in C++.

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

jesper wrote:

Quote:
C++ classes are enough reason to use C++. Classes give you modularity and scope and make understanding and reusing code easier.

Bull, it perhaps makes it a little easier, but all this is fully possible in C.
And code reuse, is still a dream, I haven't seen ANY advantages in real life with C++ in that respect. I hardly see any code reuse at all, actually, apart from more common copy/paste.

I think classes make the code easier to write, easier to read, easier to debug and easier to re-use. It does take time for a C programmer to learn to think in terms of C++ and for some people, especially those who only program small microcontrollers, it probably isn't worth the effort to switch, but that doesn't mean that C++ isn't better.

I'm not sure of the exact definition of re-use. I would think that using templates and using the Standard Template Library would be re-use. Those things are very good for big PC programs but I suppose aren't of much use on the AVR. I'd rather copy and paste C++ code than C code.

Here are a few paragraphs from Stroustrup:
What is so great about classes?

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

jesper wrote:
Quote:
Class constructors are a good thing also. Almost every module needs some initialization and that's what the constructor is for. When I look at C code I see things like ADC_init(). That begs the question of where and when it's called. With C++ there are no questions. The constructor is called when the class is constructed.
ADC_init is called where it says ADC_init() in the code. No different from the constructor.

When I look at a class, I can assume the constructor is called precisely once and called before any of the other functions are called. Looking at ADC_init() doesn't tell me that. Of course programs that work can be written in C. I did that for many years. But now I do it better and faster.

jesper wrote:
Actually, if the constructor did the initialization, you could only have one object instance (unless protecting the initialization with a static member flag).

Yes, I think most of my classes are instantiated only once.

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

jesper wrote:
Quote:
C programmers say they can write modular code, but it's easier to write and easier to read with C++.

That's probably true if you know C++ well, otherwise it can get VERY weird. The opposite is just as true.

Yes, I encountered some code that apparently was written by someone who was trying to learn C++, or maybe his boss told him he must use C++. It was indeed weird. I re-wrote the thing.

When I compare C with C++ I'm thinking of C written by a good C programmer and C++ written by a good C++ programmer.

I think being a good C++ programmer simply means knowing how and why to use classes, understanting class scope and enums, and probably a few things that don't come to mind right now. Other things can come later. I don't use much else in my AVR code and some of the features of C++ wouldn't be of any use on the AVR. The beginner should not even think about virtual functions, templates, etc..

jesper wrote:
C++ is a much more "safe" language in that respect. To the extent that you're about to go nuts over warnings for simple "shortcuts"..

I'm much saner today than I was when programming in C. :)

P.S. My code doesn't produce any warnings. I guess that comes with practice. Oh I just remembered, there's a PC program that throws a couple of "couversion from double to int, possible loss of data" warnings. I'll fix that one of these days. Or maybe not. It seems to work just fine. :)

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

jesper wrote:

Quote:
In C, scope is file scope or compilation unit scope. Looking back at that, it seems childish. :)
extern vs. public ?

I didn't write that very well, and I don't remember the nuances of C scope, if I ever did know. In C++ there is class scope and global scope. In a good C++ program there are very few if any globals. That's true for PC programs anyway. In AVR code I will sometimes use a global for a class instance pointer.

Well maybe in C++ you could give a non-class object file scope with the "static" thing. I guess you can do anything in C++ that you can do in C, but the idea boggles my mind. :)

C++ programs don't use many macros because the scope is all wrong. I think of them as global but actually it's stranger than that. It's everything in the header file following the #define(or whatever), plus every header file included after this header file is included, plus the rest of the source file that follows the include statement.

I have that burned into my brain because I once used a "#pragma pack" in a header file for a program compiled with Microsoft's compiler. I later learned I could regain my sanity by using #pragma pack(push) and #pragma pack(pop). I also learned why the GCC gurus say it's almost always a bad idea to use pragmas :)

Last Edited: Tue. Oct 14, 2008 - 09:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

In AVR code I will sometimes use a global for a class instance pointer.

If your class is only going to be instatiated once, why not have the instance pointer as a static member of the class? (We are now very close the design pattern "Singleton"...)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
If your class is only going to be instatiated once, why not have the instance pointer as a static member of the class?

You are good Johan. The answer is "because I didn't think of it". I suppose I could give the C programmer's response. "What difference does it make?". Actually they're close to the truth I suppose, but here I am preaching class scope and I missed this one. :oops:

I've done it as you suggested in the past, but this morning I forgot all about it and did the plain old fashioned extern. (old age, you know) When I do it your way, I usually have the constructor set the value of the static class pointer with something like this:
class_ptr = this;
instead of having the code that "news" the class do it.

JohanEkdahl wrote:

(We are now very close the design pattern "Singleton"...)

I hadn't heard of that but I Googled and got a wikipedia hit.

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

Quote:

old age, you know

Yes. I know.

Quote:

JohanEkdahl wrote:

(We are now very close the design pattern "Singleton"...)

I hadn't heard of that but I Googled and got a wikipedia hit.


It's merely a way to guarantee that there is one, and only, one instance of a class. The rest is more or less technicalities. It is one of my favourite DPs as it is i) easy to understand, and ii) actually is used quite frequently (in my experiences). In a resource-challenged system I might stay away from it in favour of static members (accepting the consequences of that).

If you wanna talk more DPs we should probably fork to a thread in the OT forum.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:

If you wanna talk more DPs we should probably fork to a thread in the OT forum.

Okay. I'm interested. I might not have anything intelligent to say, but I'll read your post.

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

I'm off for a couple of days. I'll describe the Singleton design pattern, and the implementation in C++ next wee. In the OT forum.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Or you could simply buy the book "Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, and John M. Vlissides. It is well worth it.

Regards,
Steve A.

The Board helps those that help themselves.

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

Yes, but that would not go with half a promise of a new war subject: "Patterns in AVRs or not".. :twisted:

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:

Got it. Good answer.

(I now have to investigate wether avr-gcc will place a V-table in FLASH or RAM. From your answer I suspect and fear that avr-gcc will place it in RAM. This is not far fetched as the tweak of the compiler to i) place the V-table in FLASH, and ii) do the "virtual lookup" through FLASH, might be non-trivial.)

Or half-got it, actually. If the function pointer array is used like you describe then it is not the C counterpart to virtual functions. So I was in error when comparing these two. (The investigation of where the V-table ends up is still interesting though.)

Johan,
I am just having a look at virtual class functions at the moment for an atmega16.

I find that there is a 2 byte pointer in ram to my single virtual function.

Did you ever find out if there was a way to move this v-table to flash?

regards
Greg

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

Such functionality would have to be designed into the compiler.

Regards,
Steve A.

The Board helps those that help themselves.

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

A (useful) v-table changes at runtime. How could it be kept in flash only, without massive overhead ?

Sid

Life... is a state of mind

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

Quote:

A (useful) v-table changes at runtime.

Huh?!? Care to expand on that?

It is my understanding that for every class with virtual methods there is one v-table with function pointers to each virtual function. Each object points to the v-table of it's class.

The entries in the v-tables are pointing into the code segment (and in an AVR context into flash memory), so they do not change at run-time - as I understand it.

I do not have my C++ material handy at my current vista, so my tech details will have to wait until later.

While I just had a brief read, this seems to support my view: http://en.wikipedia.org/wiki/Vir... .

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

JohanEkdahl wrote:
Quote:

A (useful) v-table changes at runtime.

Huh?!? Care to expand on that?

It is my understanding that for every class with virtual methods there is one v-table with function pointers to each virtual function. Each object points to the v-table of it's class.


Your understanding is incomplete.

Did you ever try to call a virtual function from the constructor or destructor of a class, when that function is overloaded by a subclass ?

Try this:

class A
{
    public:
        A()  { f(); }
        ~A() { f(); }


        virtual void f()
        {
            puts("A::f()");
        }
};

class B : public A
{
    public:
        virtual void f()
        {
            puts("B::f()");
        }
};

int main()
{
    B b;
    return 0;
}

Sid

Life... is a state of mind

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

I am guessing that I should take this discussion as a "NO.... the vtable cannot go into flash

regards
Greg

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

Quote:

Did you ever try to call a virtual function from the constructor or destructor of a class, when that function is overloaded by a subclass ?

No. It is my understanding that while a compiler might allow this w/o error or waning it is an extremely bad habit.

Se e.g. http://www.parashift.com/c%2B%2B... .

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I'll moderate/expand a bit:

AFAIK there is nothing in the C++ sandard that actually says how virtual functions should be implemented, but as I see it there is one dominating technique, and that is v-tables. What follows is my view of how it is done in several of the well-spread compilers (e.g. GNU GCC, Mirosofts C++ compiler).

A COMMENTED EXAMPLE

class Super {
public:
   virtual void f() {...};
   virtual void g() {...};
};

class Sub : public Super {
public:
   virtual void f() {...};
   virtual void g() {...};
};

Behind the scenes 1: In any inheritance hierarchy, the compiler will insert a pointer to a v-table into the base-most class. The v-tavble itself is an array of function pointers. Taking some liberty with not being strict on the funtion pointer type, for the sake of the example we could see it as the compiler actually did this:

class Super {
public:
   VirtualFunctionPointer * __vtable;
   virtual void f() {...};
};

Behind the scenes 2: The compiler also sets up two vtables (one for each class). One can think of these a structs/classes with static initialized members. Again, taking some liberties with the notation for getting actual function pointers):

class __vtable_Super{
   static VirtualFunction * pf = Super::f;
   static VirtualFunction * pg = Super::g;
};

class __vtable_Super{
   static VirtualFunction * pf = Super::f;
   static VirtualFunction * pg = Super::g;
};

Back to our code: Now let's create an object and call a virtual function.

Your code (for the sake of where the example is going I am using dynamic allocation):

Super * super1 = new Super();
super1->f();

Sub * sub1 = new Sub();
sub1->f();

Behind the scenes 3: When the objects are created the compiler know what specific type each of them are, and thus can at that point set the hiden member __vtable to point to the v-table for that specific type:

super1->__vtable = @__vtable_Super;
sub1->__vtable = @__vtable_Sub;

Then what actually happens when a virtual function is called is generically this:

object->__vtable::specificFunctionPointer()

For the two objects and two calls avove we will effectively get

super1->__vtable::pf();
sub1->__vtable::pf();

So far we are getting the same calls as we would for statically bound functions. Of-course the power of dynamic binding (or "late binding", "virtual calls" or what you want to call it) is when we have a pointer to an object where the pointer is of a "more base" type than the actual object pointed to:

Super * super2 = new Sub();
super2->__vtable::pf();

So, in this case, while the pointer is of type Super * the object pointed to is of type Sub. Dereferencing the pointer will get you to __vtable_Sub, and using the pf function pointer will result in a call to Sub::f .

No matter how many objects you create or destroy, the v-tables will be "created" only once, and are for all practical purposes contant during the life of an executing program. With such a technique/setup you can implement virtual functions as the C++ language rules specify.

It is my belief that several well spread compilers use this (or a very similar) technique/setup.

Conclusion: v-tables per se does not noed to change at run time. In the context of avr-gcc they could very well be placed in flash.

[I sincerely hope that you can handle my liberties with the C++ syntax, and live with any minor mistakes in order for this to be a discussion of a possible implementation of v-tables and virtual calls. Please?]

That's it! Fire at will!

--Johan

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Addendum: You might argue that the C++ FAQ implies that the v-table must be able to be modified at run time, since at the time the constructor for Base is running the call to virt() becomes a call to Base::virt(), but later when Derived is running a call to virt() beomes a all to Derived::virt().

This is no indication of the v-table(s) being modified at run time. It is an indication of the v-table pointer in the object(i.e. __vtable in my example above) being modified at run time: Initialy Base::Base() sets it to point to the v-table for Base. Subsequently Derived::Derived() changes it to point to the v-table for Derived.

Again: There is no need to alter v-table contents at run time. In principle they could very well be placed in flash. In practice this might not be so easy in avr-gcc (Harvard architecture, perhaps pointer sizes, recoding of virtual call code generation to make flash accesses etc etc...).

Tecnically possible? Definitively.

Will it happen shortly? Not likely.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I didn't post that as an example of good code, I posted it to illustrate that the v-table changes.

How the change happens obviously depends on how the compiler is implemented.

Relying on how one specific compiler is implemented is generally a bad idea.

Sometimes it's very tempting, though.

Sid

Life... is a state of mind

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

Quote:
I didn't post that as an example of good code, I posted it to illustrate that the v-table changes.

That diferent virtual functions are called at different point is time at construction is no proof that the v-table changes. See my post above.

-----

The conclusions are still the same:

C++ does not in any way imply that v-tables need to change at run time.

For the specific case of GCC (ans even more specifically avr-gcc) there is no need to alter v-table contents at run time. There is nothing in principle stopping them from being placed in flash.

Agree?

-----

It is my understanding that the reason for v-tables not being placed in flash is a matter of no-one atually taken the time/energy to implement this in avr-gcc. This in turn is probablbly because there are not so many C++ users in the avr-gcc community, and perhaps that virtual functions are not much utilized, and when they are they are few and the number of classes with virtuals are few and thus one lives with it..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

You're talking about changing the compiler ? Yes, I guess that may be possible although there could be other issues.

Sid

Life... is a state of mind

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

Quote:

You're talking about changing the compiler ?

You've possibly missed a lot of the prior discussion on this. About once a week someone appears here and says "don't use C++ on an embedded micro it's a bloatfest". They point to "hidden use of RAM" as once of the reasons for this assetion. they miss the point that this only occurs when you are using one the features that makes C++ more powerful than C and if you just stick to limited C++ functionality there's no reason it should be any more "bloaty" than C. Then about once every 2-3 months this same thread occurs with the request/suggestion that vtables are constant and therefore there's no need for them to be in RAM and why can't they be located in PROGMEM with the compiler using LPM rather than LD/LDS access code.

It all comes to nought as the way avr-gcc gets new features is when someone with dedication and a strong desire add to the source a "feature" that is missing. There's plenty of talk about what should be done but never any action. (in part this is because the internals of GCC are so complex that you need a degree in logical positivism to work out what's going!).

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

I will be stubborn about this, Chauncey.

You wrote:
A (useful) v-table changes at runtime. How could it be kept in flash only, without massive overhead ?

Can we agree that the above might be seriously misleading for someone passing by here?

A useful v-table does not need to change at runtime. It can be kept in flash only, and the v-table pointer in an object is the thing that changes from pointing to one v-table to pointing to another.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Johan,

Yes, the compiler could probably be changed to keep v-tables in flash.

Cliff,

I agree that a lot of people stay away from and complain about C++ because of lacking skills. There are plenty of improvements in C++ that comes without a cost, though. Stricter type checking is one of them.

I do all my AVR programming in C++.

Sid

Life... is a state of mind

Last Edited: Thu. Aug 30, 2012 - 02:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I suppose there is another advantage to treating the vtable as a const. I think there would only need to be one instance of it regardless of how many times the class is instantiated. That would be a benefit, however marginally, for programs run on non-Harvard machines also.

That having been said, it's not important to me because I'm not short on RAM. ;)

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

Quote:

I think there would only need to be one instance of it regardless of how many times the class is instantiated.

I am under the impression that this is already so - only one instance of the v-table regardless of how many times the class is instantiated.

Do you have any indications of the opposite?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

No. I just assumed it was similar to a regular class data member.

Where else would it be located? I guess it could be like a "static" member.

I believe C++ structs/classes can be bigger than equivalent C structs because C++ structs/classes can have extra stuff hidden in them. Is that true? What is this mysterious stuff?

Pages