| Author |
Message |
|
|
Posted: Feb 05, 2008 - 02:53 AM |
|

Joined: Jan 10, 2003
Posts: 533
|
|
Hi everybody,
a couple of months ago I started with AVR and c++. It's rather painful adventure, but now most of things seems to work. So I decided to share my little experience, maybe it will be useful for you.
First thing – setup. I use AVR Studio, which is almost working with c++. Almost, because you must manually in project->Configuration options->Custom options set instead of avr-gcc avr-c++.exe to compile any of your c++ files. Just changing the extension to cpp/hpp doesn't work. Remember that if you want to debug your application you need rather to turn off code optimization (-O0). In other case debugging is extremely hard thing to do and confusing. Final compilation can be done with any optimization options.
Next thing to do is to define new and delete operators:
Code:
#include <stdlib.h>
void * operator new(size_t size);
void operator delete(void * ptr);
and implementation:
Code:
void * operator new(size_t size)
{
return malloc(size);
}
void operator delete(void * ptr)
{
free(ptr);
}
That's almost all. Almost because if you are using gcc 4.x and newer (I didn't check it with older versions) and you want to use templates, virtual inheritance and so on you must define some additional functions, which is not used now by compiler, but must be present to satisfy linker:
Code:
__extension__ typedef int __guard __attribute__((mode (__DI__)));
extern "C" int __cxa_guard_acquire(__guard *);
extern "C" void __cxa_guard_release (__guard *);
extern "C" void __cxa_guard_abort (__guard *);
Please be sure to define these functions exactly as I showed, I other case gcc could crash during compilation (segmentation fault!), and for sure your program WILL BE NOT working.
Implementation is as follow (very important too):
Code:
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {};
And last thing, if you use pure virtual functions you must define another function:
Code:
extern "C" void __cxa_pure_virtual(void);
and implementation:
Code:
void __cxa_pure_virtual(void) {};
This function is never called in normal operation. The only time this function may get called is if the application calls a virtual function while the object is still being created, which gives undefined behavior. So implementation is not very important for us.
With all this things defined I was able to compile my c++ programs without any problems, and I wish the same to you.
Greetings,
Tomasz. |
|
|
| |
|
|
|
|
|
Posted: Feb 05, 2008 - 10:25 PM |
|


Joined: Mar 27, 2002
Posts: 18520
Location: Lund, Sweden
|
|
Brilliant!
Attention moderators! Sticky candidate? |
|
|
| |
|
|
|
|
|
Posted: Feb 05, 2008 - 11:07 PM |
|


Joined: Jul 18, 2005
Posts: 62220
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| At the very least I thought Tomasz ought to repost this as a tutorial in the Tutorial Forum so it's doesn't get "lost" |
_________________
|
| |
|
|
|
|
|
Posted: Feb 06, 2008 - 04:06 AM |
|

Joined: Nov 17, 2004
Posts: 13815
Location: Vancouver, BC
|
|
Also, someone put the term "CPlusPlus" in it so that it can be found by the search function. Oh look, someone just did  |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
Last edited by Koshchi on Apr 12, 2008 - 06:09 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Feb 06, 2008 - 01:35 PM |
|

Joined: Sep 07, 2004
Posts: 2518
Location: New York State
|
|
I don't have any of the cxa stuff. I never heard of it. My virtual functions aren't pure though.
The only problem I have with virtual functions is they use a huge amount of RAM and quite a bit of program memory also.
I'm currently using gcc version 4.1.2. |
|
|
| |
|
|
|
|
|
Posted: Feb 17, 2008 - 01:06 AM |
|


Joined: Jul 10, 2006
Posts: 2654
Location: Minneapolis
|
|
These array handlers may be useful too:
Code:
void * operator new[](size_t size)
{
return malloc(size);
}
void operator delete[](void * ptr)
{
free(ptr);
}
|
|
|
| |
|
|
|
|
|
Posted: Jun 19, 2008 - 11:26 PM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
except the spurious semicolons that generate errors in pedantic + ansi mode,
Code:
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {};
,
you just made a top grade post.
I would also add '-fno-exceptions' and maybe '-ansi --pedantic -Wall' to avoid shooting ourselves in the foot. g++ AVR is uncharted minefield. Any other flags to include?
BTW in order to help newbies finding the g++ and make quicker, here is my example of Project Options/External tools that worked for me:
I:\WinAVR-20071221\bin\avr-g++.exe
I:\WinAVR-20071221\utils\bin\make.exe
The last trap is in the fact that by default printf is not supporting float numbers. However because the C++ projects can be complex, it is wise to go to Project Options/Libraries section, you might want to include
libprintf_flt
libscanf_flt
libc
libm
libobjc
but NOT libprintf_min, libscanf_min
BTW I remember the problem, when a simple code
Code:
int main()
{
DDRC=0xFF;
for(;;)
{
PORTC=0xFF;
_delay_us(1);
PORTC=0x00;
_delay_us(1);
}
}
...was not working just because I have been instancing a static class object in one of include files. It took me the whole night to find the problem, hopefully my suspicions pointed onto global objects very early. The funny part was, that everything worked when the project was big. Once I have simplified (!!!) main() function to the code above, it stopped working (freeze before main). I have hunted down the statically instantiated class in one of includes, and moved it as static object to main().
This time, however, it started complaining about lacking __cxa_guard_acquire, __cxa_guard_release.
So remember, when you make static class object in global scope, without providing these functions, the code will fail silently, depending on the actual size of the project and many other factors. |
|
|
| |
|
|
|
|
|
Posted: Jun 20, 2008 - 02:10 AM |
|


Joined: Jan 14, 2008
Posts: 1147
Location: San Diego
|
|
|
kbosak wrote:
I would also add '-fno-exceptions' and maybe '-ansi --pedantic -Wall' to avoid shooting ourselves in the foot. g++ AVR is uncharted minefield. Any other flags to include?
These will help with the code size.
Code:
-ffunction-sections
-Wl,--gc-sections
http://www.avrfreaks.net/index.php?name ... mp;t=64513 |
_________________ ~~John
TWI C source code
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 10:28 AM |
|

Joined: Dec 20, 2007
Posts: 943
Location: Portland, Oregon, USA
|
|
|
TFrancuz wrote:
Hi everybody,
a couple of months ago I started with AVR and c++. It's rather painful adventure, but now most of things seems to work. So I decided to share my little experience, maybe it will be useful for you.
First thing – setup. I use AVR Studio, which is almost working with c++. Almost, because you must manually in project->Configuration options->Custom options set instead of avr-gcc avr-c++.exe to compile any of your c++ files. Just changing the extension to cpp/hpp doesn't work. Remember that if you want to debug your application you need rather to turn off code optimization (-O0). In other case debugging is extremely hard thing to do and confusing. Final compilation can be done with any optimization options.
Next thing to do is to define new and delete operators:
Code:
#include <stdlib.h>
void * operator new(size_t size);
void operator delete(void * ptr);
and implementation:
Code:
void * operator new(size_t size)
{
return malloc(size);
}
void operator delete(void * ptr)
{
free(ptr);
}
That's almost all.
... (abridged) ...
With all this things defined I was able to compile my c++ programs without any problems, and I wish the same to you.
Greetings,
Tomasz.
This is pretty impressive (I thought I knew a thing or two about C++, but "guard"s are a new one on me).
One thing I think you have missed, though, is that delete operators are supposed to safely do nothing if they're passed a NULL pointer. So your sample implementation of delete should look like this:
Code:
void operator delete(void * ptr)
{
if (ptr)
free(ptr);
}
|
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 02:21 PM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
|
Quote:
One thing I think you have missed, though, is that delete operators are supposed to safely do nothing if they're passed a NULL pointer. So your sample implementation of delete should look like this:
Code:
void operator delete(void * ptr)
{
if (ptr)
free(ptr);
}
This is a surprise to me. I always believed since 1990 that free(NULL) is always OK, even if I almost never wrote code using this. http://www.winehq.org/pipermail/wine-pa ... 31544.html
says:
ANSI-C Standard:
----------------
The ANSI standard ANSI X3.159-1989 "Programming Language C." specifies
that free(NULL) is a no op.
"free deallocates the space pointed to by p: it does nothing if p is NULL."
Quoted from "The C Programming Language" second edition by Kernighan and
Ritchie with the subtitle "ANSI C".
This would indicate that your protection is superfluous.
BTW for nitpickers that like excess safety, the code should be:
Code:
if(ptr!=NULL)
{
free(ptr);
}
because (oh there are long and useless discussions about that) NULL dont have to be 0 numerically. |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 05:03 PM |
|


Joined: Mar 12, 2004
Posts: 1174
Location: Linköping, Sweden
|
|
|
|
|
|
|
Posted: Jun 21, 2008 - 08:34 PM |
|

Joined: Dec 20, 2007
Posts: 943
Location: Portland, Oregon, USA
|
|
|
kbosak wrote:
This is a surprise to me. I always believed since 1990 that free(NULL) is always OK, even if I almost never wrote code using this. http://www.winehq.org/pipermail/wine-pa ... 31544.html
says:
ANSI-C Standard:
----------------
The ANSI standard ANSI X3.159-1989 "Programming Language C." specifies
that free(NULL) is a no op.
"free deallocates the space pointed to by p: it does nothing if p is NULL."
Quoted from "The C Programming Language" second edition by Kernighan and
Ritchie with the subtitle "ANSI C".
This would indicate that your protection is superfluous.
Wualll, I'll be darned. This is one of those superstitious "safety measure" habits that reinforce themselves; like wearing a Shriners hat to ward off flying squirrel attacks. You wear the hat, and voilla! no squirrels! After awhile, the two seem to be correlated. No particular harm done, but you DO look silly..
I'd always assumed that free()ing NULL was bad medicine, and even have dim recollection of crash dumps from our embedded code when it tried to do so (but we used an extremely old compiler). Anyway, I thought the safety of delete-ing NULL pointers was unique to C++. |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 10:53 PM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
|
Quote:
and many C++ programmers avoid using NULL
I am sorry but this is void* argument.
Most programmers are not compiler developers and most compiler developers don't care aboutev erything the Standard says, not to mention about being familiar with avr-g++.
There is more than that:
Code:
malloc(0)
in practice behaves like
Code:
new ptr[0]
The trick is that C++
Code:
new ptr[0]
is standard sanctioned: returning NONNULL, properly aligned pointer for a single element!
Code:
malloc(0)
returning nonnull may or may not be standard.
This helps implementing some dynamic data structures, I believe.
http://gcc.gnu.org/ml/libstdc++/2005-02/msg00167.html
"
The standard defines that allocators
(and operator new) may be asked for zero bytes. They must return an
address different from any other address that they have returned that
haven't since been released. (That disallows returning 0.) Most
implementations treat a call to operator new(0) identically to operator
new(1).
" |
Last edited by kbosak on Jun 21, 2008 - 11:02 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 11:00 PM |
|

Joined: Sep 07, 2004
Posts: 2518
Location: New York State
|
|
The use of the C++ delete operator in an AVR program is generally a waste of memory, and so is using malloc and free.
It's only when you want to dynamically "churn the heap" that it is required. To put it another way, if the equivalent C program would use malloc and free, then your C++ program would also use them, via new and delete.
Balancing each new with a delete is considered good practice in programs that run on PCs, but it serves no purpose on AVR programs where there is no shutdown except a hardware reset. Actually I question if it has any purpose in embedded programs that run on PCs, but I do it just because it's "good practice".
On an AVR, just "new" everything at startup and run with what you have until the end of time or reset/powerdown, whichever comes first. |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2008 - 11:06 PM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
|
Quote:
Balancing each new with a delete is considered good practice in programs that run on PCs, but it serves no purpose on AVR programs where there is no shutdown except a hardware reset.
Sorry, short-sighted idea. In fact many efficient linear algebra algorithms require special handling of sparse matrices for max speed. This calls for dynamic data structures. In order to keep implementation of those data structures clean, dynamic memory allocation is necessary. This is the major benefit of using C/C++ over FORTRAN in scientific programming. Using advanced linear algebra/geometry/fitting/optimization algoritms is very popular in many areas, just to mention GPS receivers. GPS receivers tend to run on ARM7, but simpler versions can easily run on AVR.
Let's put it this way: you can get rid of malloc and free completely. But one day, you will write a complex data structure, that uses fixed memory pool. Next day you will find that in runtime this structure hides 20% of innovatory code and 80% of code that immitates malloc's functionality. |
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2008 - 01:23 AM |
|

Joined: Sep 07, 2004
Posts: 2518
Location: New York State
|
|
|
kbosak wrote:
Sorry, short-sighted idea.
So you are saying that any C programmer that doesn't include malloc and free in all his programs is short-sighted?
All I'm saying is C++ doesn't need malloc and free any more than C programs. If a program needs it, use it. Otherwise don't. Of course if you have excessive program memory then it doesn't matter. I rarely find myself in that situation though. |
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2008 - 01:39 AM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
|
steve17 wrote:
kbosak wrote:
Sorry, short-sighted idea.
So you are saying that any C programmer that doesn't include malloc and free in all his programs is short-sighted?
All I'm saying is C++ doesn't need malloc and free any more than C programs. If a program needs it, use it. Otherwise don't. Of course if you have excessive program memory then it doesn't matter. I rarely find myself in that situation though.
I was commetning this:
Quote:
The use of the C++ delete operator in an AVR program is generally a waste of memory, and so is using malloc and free.
|
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2008 - 06:29 AM |
|


Joined: Nov 16, 2005
Posts: 341
Location: Calgary, Alberta, Canada
|
|
OT:
Quote:
GPS receivers tend to run on ARM7, but simpler versions can easily run on AVR.
That is a somewhat misleading statement. Definition of 'simpler' and 'easily' required. |
|
|
| |
|
|
|
|
|
Posted: Jun 22, 2008 - 10:18 PM |
|


Joined: Jan 30, 2008
Posts: 168
Location: Wroclaw, Poland
|
|
|
Broxbourne wrote:
OT:
Quote:
GPS receivers tend to run on ARM7, but simpler versions can easily run on AVR.
That is a somewhat misleading statement. Definition of 'simpler' and 'easily' required.
You can use Student-Lockroom programming to achieve the result. |
|
|
| |
|
|
|
|
|
Posted: Jun 23, 2008 - 01:37 AM |
|


Joined: Nov 16, 2005
Posts: 341
Location: Calgary, Alberta, Canada
|
|
|
Quote:
You can use Student-Lockroom programming to achieve the result.
Thanks, I didn't know that. |
|
|
| |
|
|
|
|
|