avr-c++ micro how-to

93 posts / 0 new
Last post
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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:

#include 

void * operator new(size_t size);
void operator delete(void * ptr);

and implementation:

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:

__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):

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:

extern "C" void __cxa_pure_virtual(void);

and implementation:

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.

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

Brilliant!

Attention moderators! Sticky candidate?

"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]

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

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"

 

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

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.

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

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.

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

These array handlers may be useful too:

void * operator new[](size_t size) 
{ 
    return malloc(size); 
} 

void operator delete[](void * ptr) 
{ 
    free(ptr); 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

except the spurious semicolons that generate errors in pedantic + ansi mode,

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

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.

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

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.

-ffunction-sections 
-Wl,--gc-sections 

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=64513

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

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:

#include 

void * operator new(size_t size);
void operator delete(void * ptr);

and implementation:

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:

void operator delete(void * ptr)
{
  if (ptr)
    free(ptr);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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:

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-patches/2006-October/031544.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:

if(ptr!=NULL)
{
    free(ptr);
}

because (oh there are long and useless discussions about that) NULL dont have to be 0 numerically.

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

Quote:
because (oh there are long and useless discussions about that) NULL dont have to be 0 numerically.
Actually NULL has to be 0 in C++ (and many C++ programmers avoid using NULL).

http://www.research.att.com/~bs/bs_faq2.html#null
/Lars

Pages