C++ idioms for embedded systems

Go To Last Post
114 posts / 0 new

Pages

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

In another thread we (me, clawson and smileymicros) commited a threadjack, risking derailing a discussion on "Why is it hard to go from assembler to C" into a discussion on "from C to C++". I promised to start a new thread for the latter discussion, and here it is.

I'm interested in the following:

1) If you actually have used C++ for embedded systems, and you have an "idiom" (avoiding the term "design pattern" for survival reasons), then please do!

2) If you have something that you'd like to write in C++ but don't know how - let's discuss!

3) If you are coming from (typically) C and have a genuine interest in trying out C++, but have difficulties getting over the hurdles: Please share experiences or ask.

What I'd be glad to avoid here is the sweeping allegations as to the un-effectiveness of C++. We've had those over and over. Seek them out and read them first please. Well thought out examples of when C++ actually degenerates are welcome for discussion.

As usual, I'm hard pressed with work and stuff, and spend too much time ranting here at 'freaks - part of the reason my C++ demo app is only half-way, and still partly just a concept. But I'll get there, just wait. Christmas, maybe..

Anyhow - share your C++ experiences and/or questions re embedded system.

(BTW: If you just like to read some interesting and often quite good stuff on C++ in embedded systems, do go through Dan Saks' articles at embedded.com !)

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 know that C++ allows calling C functions, but what about the reverse? I have an application that is written in C, but I may need to make use of available C++ code to add extended functionality.

A C++ compilier will "downshift" to compile a C module, so it could be used to build the entire application linking in a few C++ modules? Would that work?

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

I have heard folks refer to the Arduino "language" as c++ and it clearly "works" in embedded systems. So, what's different? I know very little about c++ but would like to learn. So, please tell how you do it.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

kscharf wrote:
I know that C++ allows calling C functions, but what about the reverse? I have an application that is written in C, but I may need to make use of available C++ code to add extended functionality.

gcc: The main() function must be compiled as C++. This pulls in the necessary C++ runtime support when linking.

From there on you can call you existing C code. Proper usage of "extern C" is required in the declarations of every C function - that is functions compiled as C, not as C++, e.g. avr-libc library functions.

Porting and recompiling your whole code as C++ is the better option than continue compiling your existing code as C code.

Instantiating and calling C++ objects from C is a pain. You will need to write C-style (no hidden this parameter involved) wrapper functions around the classes you want to deal with. And compile the wrappers as C++ (not C). Your C code can then call these wrappers.

Stealing Proteus doesn't make you an engineer.

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

Johan,

I'll start the debate by asserting: the Arduino Serial library does not fully use the object oriented features available with C++.

What I think could be done is that a real object oriented approach would look first at what embedded serial output is and design the functions around the high level concepts - not paying any attention to the underlying hardware or existing C library functions. And only after designing the specified Objects would he look at what is available to implement those objects.

I say this mostly because I don't know what I'm talking about and I'd like to know enough about real OO using C++ that I could support or counter my argument about the Arduino Serial library with facts. So if some one who thinks they really know OO wants to look at that library and tell me why it is or is not 'good' OO, I'd love to read it.

I wonder if this has already been addressed for embedded systems where someone shows code that is slightly evolved C written in C++ versus code written from real Object Oriented specifications that preceded any actual coding.

Smiley

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

OK, this raises several questions:

1) There must be c++ "syntax" that is different from c, or is it "just" a superset of c?

2) Is the object stuff a necessary part of c++ or can programs be written in c++ without using objects (as Arduino code appears to)?

3) Any sense of the overhead imposed by use of objects? Many of us have a sense, now, of the overhead for using c (parameter passing stacks and variable protection when starting into or returning from an ISR, for example).

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

ka7ehk wrote:
OK, this raises several questions:

1) There must be c++ "syntax" that is different from c, or is it "just" a superset of c?

2) Is the object stuff a necessary part of c++ or can programs be written in c++ without using objects (as Arduino code appears to)?

3) Any sense of the overhead imposed by use of objects? Many of us have a sense, now, of the overhead for using c (parameter passing stacks and variable protection when starting into or returning from an ISR, for example).

Jim

Uh, even if it were "just" a superset of C, there would have to be syntactic differences, wouldn't there?

I'm not expert enough to be able to come close to a complete list, but here are a few differences (most of them advantages of C++) between the two that led me to base the current project I'm working on in C++

    +) You can "overload" functions - that is, have several different kinds of parameter lists for the same function name. Usually, you'd do this for a group of methods in a class or structure. If it makes sense for some object or library function to work with more than one kind of 'raw material', I think it can help the program's readability if the same function name is used in each case
    +) (related) Functions can be given default arguments, simplifying their use in "typical" situations
    +) References! My software developer colleagues where I work have evolved a style that tends to make each variable and function name a grammatically correct sentence (just minus all the vowels) that tries to explain what's going on. And they don't seem to mind writing stuff like
    aTopLevelPtr->someField.anotherMember[2].firstSubfield = 1;
    aTopLevelPtr->someField.anotherMember[2].secondSubfield++;

    , and on and on, endlessly repeating the same description of how to drill down to that leaf-node nugget of information they want. I'm fond of factoring out those drilling operations by setting up a C++ reference; it (IMHO) improves readability, and also seems to pound a clue or two into the compiler that helps it avoid repeating all the dereferencing folderal:

    LeafNode& theLeaf = aTopLevelPtr->someField.anotherMember[2];
    theLeaf.firstSubfield = 1;
    theLeaf.secondSubfield++;
    

    Yes, you could use pointers for that too, but references are nailed down tighter (C++ doesn't ever let you change what a reference points to the way you can manipulate a pointer), and the compiler seems to be able to optimize its uses better

    +)Automatic typedef-fing I know that can't be the correct terminology, but in C++ you don't need to keep going
    typedef struct sName { /* contents */ } tName;

    ; simply doing

    struct tName { /* contents */ };

    is enough. Same for enums, structs, and unions.

    +) Namespaces. With C++'s namespaces, you can almost even make enumerations work as they should. If you wrote an enumeration like this in C (or C++):
    enum anEnumKind { aValue, anotherValue, yetAnother };

    , all the enumeration IDs have to compete for individuality in the global namespace along with other variables and enumerations. Some enumerations naturally tend to be unique, but Heaven help you if you want "OFF" to appear as a choice in two different enumerations. Well, with C++ namespaces, you can write:

    namespace anEnumKind { enum Enum { aValue, anotherValue, OFF}; }

    , and now that enumeration's version of 'OFF' is known as anEnumKind::OFF, which can be distinct from lampIntensity::OFF

    +) C++ actually recognizes 'bool' as a builtin type, kind of.

As for whether "the OO stuff" has to be used: No, you don't have to arm your structures or unions with their own sets of interface functions. With the gnu C++ compiler for the AVR, I'm too frightened by what it means for objects to have virtual function tables (where do they go? FLASH or SRAM?) to dare try any polymorphic stuff, or dynamic construction either, for that matter. Static construction seems to be OK, though.

And as for the overhead question, C++ seems to be pretty fanatical about upholding the same "pay only for what you use" ethic of C. If you stay away from virtual functions, I don't think there's any penalty for coding in C++.

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

I think most people switching over to C++ tend to over-objectize everything.

I don't yet see much reason to use C++, but I think it's great for stuff like buffers, queues, stacks and such, combined with templates.

OOP could also be handy to handle multiple identical peripherals like UARTS or timers.

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

OK first silly question:

LeafNode& theLeaf = aTopLevelPtr->someField.anotherMember[2]; 
theLeaf.firstSubfield = 1; 
theLeaf.secondSubfield++; 

What is the purpose of the ampersand in that?

And to Jim's comment:

Quote:
I have heard folks refer to the Arduino "language" as c++ and it clearly "works" in embedded systems. So, what's different? I know very little about c++ but would like to learn. So, please tell how you do it.

It's true that Arduino .pde files (Sketches) just translate to a .cpp (C++ source file) before being passed to avr-g++ (the avr-gcc C++ compiler). So in that sense they are true C++ programs. The only "odd" thing about Arduino that makes it not "totally C++" is simply the fact that the programmer does not provide main(). The first step of using the .pde is to wrap it in a C++ program that says:

#lots_of_includes

int main(void) {
  arduino_internal_init();
  setup();  // one of the two functions in .pde
  while(1) {
    loop(); // the other function that must be in .pde
  }
}

As I said in the other thread it's Arduino that's possibly persuading me of the merit in exploring C++ further not because of variable parameters to functions or function defaults or operator overloading but simply the "method" access to functions.

Everything related to Serial is invoked with Serial.something(). So instead of Serial_init(9600) it uses Serial.begin(9600). And instead of Serial_write() it uses Serial.write() and so on. This may seem a small detail but it imposes a stronger methodology on function naming because anything to do with the Serial class will be named Serial.???, without is you can have Serial_init(), Uart_putchar, RS232_sendstring() and they all relate to the same module. (or coding standard wouldn't permit this bizarre naming scheme but I see many such examples here and in existing codes).

No doubt other C++ functionality could be used in Arduino. Like having a Serial.begin() that can be used as Serial.begin(9600) or Serial.begin(9600,8) or Serial.begin(9600,8,1) etc. but on the whole it doesn't appear to be. It appears they just use C++ to give a more consistent interface to C programmers (it seems).

In all the Arduino sketches I've seen I've never seen use (apart from x.y()) of other C++ syntax I don't recognize the function of.

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

hi all,

i want to share some of my little experience on c++.

Many people think to C++ as OOP is a mandatory feature to use, or thinking to MSVC++ / C++ builder way of doing things, and so.

C++ is a very wide and complex language. It is standard, so don't depend from any IDE, and not all compilers are close to the standard.

I have years of experience and still missing many aspects of it. I suggest anyway to buy a cheap copy of the very famous "The C++ Programming Language", from Stroustrup, i never read it all but is very useful as a bible.

A first start with C++ is not using objects at all.
Some facilities offered are:
- variables declaration everywhere in the scope
- function overloading
- enums
- namespaces
- c++ castings (dynamic_cast, reinterpret_cast ...
- references
- .. some others,

All these basic features are not requiring to use objects at all, and they add some powerful in programming whit low (should be low, to be verified on avr) code overhead.
Namespaces are very important to separate for example a library user interfaces from the developer interface.

Object introduction come when a nice structure mostly for very wide programs is required, to allow better understanding and maintaining of the program. Writing code in object require more time than write down raw C, but you can delegate a task to every object, and have a better maintenance than in plain C, almost on very big projects.

Let's see a basic data object, useful for organizing/maintain objects.


struct mydata {
 mydata () { testvar = 1; } 
private:
 uint16_t testvar;
};

This simple data object shoud not really take very few opcodes overhead than similar code in plain c.

Different is when we start to use design patterns, virtual methods, hineritance etc etc,

About patterns, i don't like and don't belive so much on them, best thing is not forcing on use them at every cost.
I mostly like the wonderful Singleton object, for single hinstances, my preferred way is.

class Singleton {
    Singleton () {};
public:
    static Singleton &get() { static Singleton s; return s; }
};

I generally use it to keep global settings/methods visible to all the other objects avoiding to pass pointers/references here and there.

I never tried c++ on avr, but will be very happy to try on my next project and share experience.

Reagrds,
angelo

Angelo

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

Quote:

- enums

Can C++ claim that? Or are C++ enums somehow "better" than those in standard C?

As for the other things you listed. Can we have an example of each and the reason why we'd actually benefit from using them?

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

Quote:
OK first silly question:
Code:
LeafNode& theLeaf = aTopLevelPtr->someField.anotherMember[2];
theLeaf.firstSubfield = 1;
theLeaf.secondSubfield++;

What is the purpose of the ampersand in that?

There are no silly questions, only silly answers. The '&' creates a reference to the, hmm, referenced object and can be used 'identically' as the original object. But, it's not a pointer, it can't later be changed. Also it has it's own 'lifetime' and is actually an object itself.

As for an earlier comment about dynamic allocation (in object construction) I thought the avr-g++ compiler didn't support the 'new' keyword?

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Quote:

There are no silly questions, only silly answers. The '&' creates a reference to the, hmm, referenced object and can be used 'identically' as the original object. But, it's not a pointer, it can't later be changed. Also it has it's own 'lifetime' and is actually an object itself

So what's its advantage over a pointer then? Is it purely that it is read-only?
Quote:

As for an earlier comment about dynamic allocation (in object construction) I thought the avr-g++ compiler didn't support the 'new' keyword?

It does but the point is that the user has to implement 'new' themselves (using malloc() ). There's been a number of prior threads about this and I suspect it's mentioned in the C++ sticky at the top of the GCC forum.

EDIT: it turns out that it was the very first thing mentioned at the top of that sticky in fact ;-)

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

Quote:
So what's its advantage over a pointer then?

Hmm, I'm not sure anybody said there were advantages to using them, just that they arn't the same thing.

From 'NutShell'.... A Reference, unlike a pointer, cannot be made to refer to a diffrerent object at runtime. Assignments to a reference are just like assignments to the referenced object'

Also... Function arguments are passed by value in c++, which requires copying the arguments. (Copy is a costly thing to do) so passing a reference to a large object yields better performance (than passing the object itself).

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

hi all,

clawson, very happy to be useful some time, since i am not still very useful on avr help :)

Sorry, i added enum, that already exist in C. Anyway it is slightly different in c++. It is a user define type that support operators also.

I try to do some simple samples as yuo asked.

Don't forget c++ is standard. And many compilers are very close to the standard, like g++, and hopefully avr-g++. Was not the same for example for M$VC++ and Borland C++, even if nowaday they moved to be more standard.

My code below is standard, and should run fine on a standard compiler, but is untested.

Sample 1 - variable declaration


(C)

void f() {
   int a,b,c;

   a=1;
   for (b=0;b<10;++b) { c=c+1; }
}

(C++)

void f() {
   int a;
  
   a=1;

   int b,c;
   for (b=0;b<10;++b) { c=c+1; }
}

Some C compiler already allow this, but don't forget this is one of the most basic C++ feature.

Sample 2 - function overloading


(C++)

void copy (int a, int b) { .... }
void copy (struct abc s1, struct abc s2)  { .... }

void init () {
struct abc a, b;

copy (a,b);   // automatically call the second method
}

Sample 3 - namespaces


amespaces.hh

namespace utils {

void myFunc1 () {...}
void myFunc2 () {...}
void myFunc3 () {...}

};

// main program scope ...

#include "namespaces.hh"

using namespace utils;

void init ()
{
 myFunct ();

 // or

 utils::myFunct(); // if you don't use "using"
}



This help to divide code in logical groups, namespace functions can be called here only with utils::myFuncX(), or with "using namespace utils; or even better, use utils::myVar to enable that variable only.
There are many cases where it's useful to group functions/vars, they can also have the same name but pertain to different namespaces.

Castings is quite complex for a simple sample, but for example castings like "const_cast" can remove constness from a variable.

Enums as i said are objects also, so operators as ++ << >> can be written as well


enum Day { sun, mon, tue, wed, thu, fri, sat };
Day & operator++(Day &d)
{
   return d = (sat==d) ? sun : Day(d+1);
}

Then come the reference. It is another basic feature that should be typical c++. It can be used in a safer way than a pointer to pass objects/vars reference. Difference with pointers it that for his nature the compiler don't allow uninitialized reference vars, so it is guaranteed there are no invalid references.


// lets invent a reentrant function ...

int divide (int &a, int&b)
{
   return a/b;
}

 ...
 int a, b;

 divide (a, b);

...

//it is different than use 

int divide (int *a, int*b)
{
  return *a/*b;
}

In the second case it is sure the variables are there.

I don't have too much time now to go on with samples, but i can go deep later after job time.

regards,
angelo

Angelo

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

Quote:
I thought the avr-g++ compiler didn't support the 'new' keyword?

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
Quote:

It does but the point is that the user has to implement 'new' themselves (using malloc() ).
Then it doesn't, surely? The suggested 'workaround' is a programmer supplied implementation not a compiler supported function. Without support for libstdc++ there would be several things missing (which a programmer could supply him/herself, if so inclined.) :)

But thanks for the pointer, it's all usefull information.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

I used to do a lot of turbo pascal and you could have a module with an interface and an implementation, and you could 'use' the module interface and 'with' the long record of identifiers separated by dots. Then they started pushing Ada, and I noticed it was about the same, but the with and use was swapped. C++ has the same concept, but different names instead of interface and implementation. I think Bill Joy invented java to be 'c without pointers' and its full of the same oo lingo like objects and classes and instantiation. Only hi level oo thing I know so far is that an object is a class that gets newed. It is like a struct with data fields, but it also has the little method procedures that get and set the data parts. Some compsci could make a big chart showing the similarities between c++, java, and ada.

Imagecraft compiler user

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

Quote:
Only hi level oo thing I know so far is that an object is a class that gets newed.

Thats pretty close :) An object, is a struct(ure) that contains it's own data AND the methods that minipulate that data. So, for instance, a SERVO object (read class) could contain the current position and a method for altering it. (Thats the 'ecapsulation' part of O-O.) The user of the SERVO object (thats you, btw) could use 'SERVO.position(25)' and totally not care about 'how' it sets the position to 25, just that it does. Conversly you could (theoreticaly) 'int pos = SERVO.getposition()' and... well, you get the gist :)

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Quote:
very happy to be useful some time

First a HUGE thank you for this. I've kept asking for such examples for many moons here but nothing has been previously forthcoming.
Quote:

Sample 1 - variable declaration

Oh dear God, it was C++ that foisted that abomination on the world was it? I cannot think of anything worse than not having all the variables defined at the very top of a statement block. Who in the world ever thought there'd be an advantage to mixing them in the middle? When you see a segment of code with 'foo' being used your natural reaction is to look back first to the start of that block, then the start of the function then the start of the file to find the variable definition. Allowing them to be mixed into the code just obfuscates it. I suppose people will say that with modern source browning editors it doesn't matter because the editor will show the type definition wherever it's located but you aren't always using such an editor when looking at code.
Quote:
Sample 2 - function overloading

Now this I like and I can definitely see the added utility of over C.
Quote:
Sample 3 - namespaces

Now this just formalises the kind of structure our coding standard imposes anyway but I guess it's nice to have it policed by the compiler.

Day & operator++(Day &d) 
{ 
   return d = (sat==d) ? sun : Day(d+1); 
} 

Sorry but can you explain that syntax little more. What is the smattering of ampersands achieving in that? Also what does the ++ achieve when it seems to appear in something like a function prototype?

I look forward to more of your posts. This kind of approach may finally get me over the hurdle! (cf the Asm->C "hurdle" that was discussed in the other thread that spawned this one)

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

Quote:
Also what does the ++ achieve when it seems to appear in something like a function prototype?

This in c++ is called operator overloading. The ++ operator is an object function (increment), so you are supplying your implementation of the increment operator for the Day object. (Does that make it any clearer, or am I just confusing matters more?)

Lets see... Day x = Day.mon; (x++ would return Day.tue)

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

Last Edited: Thu. Nov 25, 2010 - 03:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Does that make it any clearer

Sad to say but it doesn't - remember that I'm a tyro. I understand operator over-loading (I think) but I don't understand your use of "your implementation".

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

Quote:
but I don't understand your use of "your implementation"

The Day object (or in this case, enumeration) has no predefined operations. So '++' is not actually implemented for a Day object. In the code snippet, the programmer has supplied the implementation for the increment operator. Hence 'your implementation' (being the programmers implementation).

A full implementation would also (presumably) need such other overloads as '--' to go back a day, '==' does object a equal object b, '=' assignment (one object gets a copy of another) etc..

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Oh right, now I get it - that IS clever!

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

Quote:
Oh right, now I get it - that IS clever!

*phew* I was worried I was making matters much worse. I'm a software engineer, don't you know, NOT a teacher! :) :) :)

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

ka7ehk wrote:
2) Is the object stuff a necessary part of c++ or can programs be written in c++ without using objects (as Arduino code appears to)?
Some people say that C++ without objects can be thought of as a "better C". For example, C++ has stricter type checking than C does. One example of that is the handling of enums. In C, enums are a thin veneer over an integral type but in C++ they are full-fledged types in their own right.

A number of years ago I set out to learn C++ after programming in C for 20+ years. I found Ira Pohl's book C++ for C Programmers and Bruce Eckel's book Thinking in C++ very helpful for making that transition. The Stroustrup book mentioned earlier is useful as a reference but it is not well suited for learning.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

clawson wrote:
Everything related to Serial is invoked with Serial.something(). So instead of Serial_init(9600) it uses Serial.begin(9600). And instead of Serial_write() it uses Serial.write() and so on. This may seem a small detail but it imposes a stronger methodology on function naming because anything to do with the Serial class will be named Serial.???, without is you can have Serial_init(), Uart_putchar, RS232_sendstring() and they all relate to the same module. (or coding standard wouldn't permit this bizarre naming scheme but I see many such examples here and in existing codes).
I hope you are wrong about this. I am investing a lot of time building a library that will help Arduino users transition to regular Atmel tools: AVRStudio/WinAVR/avrdude. The first step for my library is an elementary section where the functions look like the Arduino functions but work directly regular tool. I have all the Serial.xxx functions renamed as serial_xxx. To the Arduino set I'm adding serial_printf() as a wrapper for the standard C printf function with the stream callback and a FIFO hidden from the user.

void serial_begin(uint32_t baudrate);
Sets the baudrate and initializes the fifo, usart, and device (if needed).

void serial_end(void);
Set USART registers back to default values.
Deactivate the ISR

uint8_t serial_available(void);
Returns the buffer length so this can be used as a boolean query since a buffer length of 0 is boolean false.
\return uint8_t the buffer.length. 

uint8_t serial_read(void);
Reads a byte from the buffer
\return uint8_t byte read
\todo Improve error checking - what happens if you read
	an empty buffer?

void serial_flush(void);
Flushes the buffer by reseting the length and index. This is protected from usart ISR put bytes. This does not set the bytes to zero.

void serial_write(uint8_t *buff, uint8_t size);
Sends bytes from a buffer of a given size out the usart.
\param uint8_t *buff pointer to a buffer
\param uint9_t size size of the buffer


#define serial_printf(val1, val2) printf_P(PSTR(val1),val2);
This is a macro that hides vfprintf_P – and you don’t want to know any more than that when using elementary ‘functions’.
TODO: THIS IS WHERE YOU GET TO GO ON FOR PAGES ABOUT FORMATTING

I intend to show how each of these functions is implemented in C and I certainly don't think jumping a novice learning C into C++ would be a wise introductory technique. I have a feeling that Arduino novices peek under the hood and see all the C++ and get even more frightened of programming than they might if it was just more C like the high level Arduino stuff.

Again if you are correct that Serial.xxx is somehow easier for a novice to understand than serial_xxx then I'm wasting my time, but I personally don't see the difference from the perspective of a user.

Smiley

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

dkinzer wrote:
... and Bruce Eckel's book Thinking in C++ very helpful for making that transition.
This is the book that leads me to often assert that embedded C++ is often just dressed up C and doesn't really use the OO that C++ was invented for.

dkinzer wrote:
Some people say that C++ without objects can be thought of as a "better C". For example, C++ has stricter type checking than C does. One example of that is the handling of enums. In C, enums are a thin veneer over an integral type but in C++ they are full-fledged types in their own right.
I'm going to have to give this some thought - this a is pretty convincing argument and I might moderate my stand since this seems a good reason to accept non-OO half-C++ as a valid way to use it. Maybe I'm being too picky saying folks aren't using C++ properly when they use it to dress up C, maybe that is a good enough reason?

Smiley

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

Quote:
Maybe I'm being too picky saying folks aren't using C++ properly when they use it to dress up C, maybe that is a good enough reason?

The simple fact that it is 'more' strongly typed, should (IMHO) be reason enough to use it :)
Also, it's simply not possible to pass a null reference to a function in c++ (unless you happen to enjoy outsmarting the compiler) because references are assigned at compile time not run time and the compiler will throw the book at you if you try to create a reference which does not refer to something! Where in 'c' a pointer type can happily be null and everybody is happy (until you actually run the code) :)

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Quote:
I intend to show how each of these functions is implemented in C and I certainly don't think jumping a novice learning C into C++ would be a wise introductory technique. I have a feeling that Arduino novices peek under the hood and see all the C++ and get even more frightened of programming than they might if it was just more C like the high level Arduino stuff.

But Arduino is c++ not c!
It just has a boat load of libraries and several simple api's into the nitty gritty.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void serial_begin(uint32_t baudrate);
Sets the baudrate and initializes the fifo, usart, and device (if needed). 

And how do you initialise serial ports 2,3,4 if the device supports them?
Thats the reason OOPS was developed... to encapsulate the data and control logic in an object. In this case called Serial. If the device supports it, in c++ you would add another by simply... Serial myNEWSERIAL and bingo! another serial port springs into existance with all the functionality of the original blueprint.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Really appreciate the comments, above. Lots to digest, here!

OK, back to the "overhead" bit......

If you overload a function, is the resolved by the compiler or is it dealt with at run-time? I suspect that this could have major implications on use of codespace and execution speed (which are, as "we all know", are important questions in many micro-controller systems).

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

ka7ehk wrote:
If you overload a function, is the resolved by the compiler or is it dealt with at run-time?
In a non-object context and with non-virtual methods of classes, the compiler/linker resolves the linkage at build time. There is no run-time overhead.

As a side note, in order to support function/method overloading the compiler performs "name mangling" on the function name. For example, a function named foo may have its name mangled to _Z3fooh internally. However, the mangled names also appear in the .lss and .sym files making it somewhat more difficult to debug using these files. The name mangling is employed even if a function is not actually overloaded unless the function is defined as extern "C" (i.e. having C linkage attributes). Note that an extern C function cannot be overloaded.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

$SON-OF-DEITY!

I started this thread yesterday, and then went off to lead an educational event for one day, and come back to this. I've used up all my energy today so I wont even start to read all the posts in this thread. Tomorrow is a normal work-day so this will have to wait until the week-end, but I promise I'll read through it all then and try to responds to anything that has not gotten an answer yet.

Very exiting! [off to look though other posts]

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

kscharf wrote:
I know that C++ allows calling C functions, but what about the reverse?
It can be done. If the C++ function is defined with the C linkage attribute (extern "C") then it is easy. Otherwise, it is more difficult.

The first difficulty arises due to "name mangling" - a C++ function named foo() may have a name like _Z3fooh internally. I don't know if there is a way to predict/control what the mangled name will be or if it will be different from one compilation to the next (say, when an overload is added).

The second difficulty is that non-static class member functions have a hidden parameter (the object reference, aka the "this pointer") that the compiler provides automatically. If you're calling the non-static member function from C or assembly language you have to provide the "this pointer" parameter yourself.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

Last Edited: Thu. Nov 25, 2010 - 07:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

In C, enums are a thin veneer over an integral type but in C++ they are full-fledged types in their own right.

But in C I always use:

typedef enum {
 IDLE = 36,
 ON,
 OFF
} state_t;

state_t fred;

'fred' is then a typed variable and there will be warnings about incorrect type usage.

Quote:

Again if you are correct that Serial.xxx is somehow easier for a novice to understand than serial_xxx then I'm wasting my time, but I personally don't see the difference from the perspective of a user.

Joe, no worries. My point was that in the C you could rename your serial_flush() to my_aunt_fanny_likes_to_tap_dance() and it would still work the same. C++'s "class" system wouldn't allow this - it enforces everything to do with the Serial module to start Serial-something. Which is nice. But not an absolute necessity. You see I think a lot of the things that C++ casts in concrete are probably self-imposed rules a lot of us have been applying when writing C (in our case because of a coding standard). It's just that C++ seems to implement a way for the compiler to formally police such rules.
Quote:

And how do you initialise serial ports 2,3,4 if the device supports them?

I was looking at Arduino earlier. In HardwareSerial.h it defines the HardwareSerial class, then it simply does:

extern HardwareSerial Serial;

#if defined(__AVR_ATmega1280__)
extern HardwareSerial Serial1;
extern HardwareSerial Serial2;
extern HardwareSerial Serial3;
#endif

I can definitely see the appeal of that.

Quote:

In a non-object context and with non-virtual methods of classes, the compiler/linker resolves the linkage at build time.

It's sentences like that which make me head for the bunker! Wot? :-O

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

Hi clawson and all,

very happy to share what i know.

Well, variable definition here an there is not nice to see, but in c++ is commonly used, mostly becouse you don't need to care where you are in the scope. Then for optimization effect, at run time them should all be probably allocated togheter in the stack frame.

Most frequently you will see:


class ObjectX {
  ObjectX () {}
};

class ObjectY {
 int variable1;
 int variable2;
};

ObjectY::Constructor () 
{
   varaible1 = 0;
   variable2 = 1;

   ObjectX *x=new ObjectX();

   .....
}

so it is typical in C++ to see variables or pointers allocated here and there, and at the long run even not so bad for the eyes :).

Namespaces, yes they are useful for logical ordering, and also in very big applications. It is the first and simple way to achieve some modularity.

About Day sample, let's see some reference (&) usage before:


class ObjectQ {
   int a;
   int b;
   int c;
public:
   void FuncA () { a=b+c; }
   void FuncB () { b=c+a; }
   void FuncC () { c=a+b; }
};

// this function return a complete ObjectQ  (sizeof ObjectQ)
ObjectQ getQ1 ()
{
   ObjectQ q;

   return q;
}

// this function return the reference to an ObjectQ object.
// Reference sice is just for example 16 or 32bit, as a 
// pointer.
// In c++ references are mostly preferred than pointers, 
// everytime is possible.  

ObjectQ & getQ2 ()
{
   Object q* = new ObjectQ;

   return *q;
}

int main ()
{
 ObjectQ q1 = getQ1 ();
 ObjectQ q2 = getQ2 ();

 // these 2 variables q1 and q2 will be the same
 // but getting Q1 is much slower.
}

Creating a simple object with constructor:


// C++ syntax to create an object is:

class Object {
public:
   Object (int a) { var=a; } // constructor

private:
   int var;
};

// constructor is the first method automatically called 
// when an object is allocated.

int main () {

  int value=1;

   Object1 o(value); 

   // object name "o", of type Object1 has been allocated
   // and initialized to value inside his constructor.

   // Object1 will live until the function scope and then will  
   // be estroyed. 

}

// Lets see now the Day example:
// Day is a type and in C++ all types (also an int) can be
// created like objects:

enum Day { sun, mon, tue, wed, thu, fri, sat };

// The operator function typically get a reference to an object
// as parameter and return a reference of the same object but 
// with a modified value.
// This because it will be used as  o++ where "o" ref. is passed
// and his value will be modified and returned.

// The syntax Day(d+1) is used to create an object on the fly
// without giving to it a name.

// operator++ is the way to create a new operator for the Day 
// type. We can also create a --, =, << or >>, to behave just as 
// we want.

Day & operator++(Day &d)
{
   return d = (sat==d) ? sun : Day(d+1);
}

int main () {

  int a(1);  // allocate a and initialize it to 1

  Day d(sun); // create a Day type initialized to d.

  Day c=sat;  // same effect as above

  c++;   // after this line c is "sun"
}

another nice/simple thing of c++ is that it introduce new types, like "bool" :) This is something C don't have, for a boolean value you have to use a char :) . I am not sure but "bool" instead should also be treated as a bit from the compiler, depend from the compiler implementation.

Will find out some other useful and simple samples.
I am sorry to know avr-gcc don't have new. But are you sure ? i found this man page :
http://ccrma.stanford.edu/planet...
and from here seems to be available, but i will check probably later.

regards,
angelo

Angelo

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

Quote:
It's sentences like that which make me head for the bunker! Wot? :-O

You got room for me in that bunker? :)

I think the poster is hinting at the dynamic use of the v-table. Where at run time, the 'system' determines which actual method to call, determined by the actual type of object is being passed into a function call. The subject of inheritance is a little complex for a quick forum post, but two different objects can be based (inherited) from a third object ( base class) which simply defines a method as virtual (which means that any derived object must supply it's own implementation of the method). At run time, something somewhere has to determine which 'version' of the method actually needs to get called, based on the actual (concrete) class that was supplied by the caller. Umm.. I'm not being very clear again, am i?
Think of an abstract class called 'fruit'... it defines a virtual method called 'peel' (but does not implement a method for peeling fruit, because each 'fruit' would essentially need it's own way of getting peeled). Ok, so now we derive an 'apple' and a 'banana' from the base class 'fruit'. When written, we would have apple.peel() and banana.peel() each of these would implement .peel() slightly differently.
Now the crux... when we wish to use the apple or the banana in our 'eat' function, we can actually pass in either a apple or a banana. The function in the program we are calling, only needs to know that it's a 'fruit' that its getting passed. So it calls the .peel() method of 'fruit'. The v-table(s) of the object contain the pointers to the actual code that needs to be executed so both method versions are compiled in. This is all sort of linked at run time (bad explanation but I hope it helps).

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

clawson wrote:
will be warnings about incorrect type usage.
No warnings will result from what you've done. You've just told the compiler how to represent the enum values internally. The problem would arise if you later wrote:
fred = 675;

The issue arises because 675 doesn't have the type state_t. A C compiler won't utter a peep about this type of thing but a C++ compiler will issue an error such as:

error: invalid conversion from 'int' to 'state_t'

. If you want to overrule the compiler (inadvisable at best), you have to use an explicit cast:

freg = (state_t)675;

or, preferably

fred = static_cast(675);

Both casts accomplish the same thing. The newer form of cast shown in the second case is considered preferable because it can be easily identified using automated tools and advanced editor search capabilities.

Quote:
Quote:
In a non-object context and with non-virtual methods of classes, the compiler/linker resolves the linkage at build time.classes, the compiler/linker resolves the linkage at build time.
It's sentences like that which make me head for the bunker! Wot? :-O
Sorry. I could have omitted the mention of virtual methods (which implement run-time linkage). Unfortunately, with the extra "power" that C++ (and O-O generally) bring to the table there is necessarily more complexity. The good news is that if you don't specifically ask for a method to be virtual it won't be.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

gregsmithcts wrote:
I think the poster is hinting at the dynamic use of the v-table.
Exactly. ka7ehk asked if linkage to overloaded functions was resolved at link time or run time. Perhaps I should have said that they are resolved at link time (except for the special case of virtual member functions).

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

spectrum wrote:
I am sorry to know avr-gcc don't have new. But are you sure ?
You can use new but you have to write your own implementation (e.g. as a wrapper on malloc()). The problem is that in standard C++ new will throw an exception if it can't allocate the requested block. In your own implementation you have to decide what to do if the allocation fails.

See the avr-c++ HowTo for more information.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

I have used GNU C++ compiler for AVR with a few projects and have later gone back to C for the following reasons:
1. Only a small subset of C++ is supported.
2. There was only a couple of KLOC of code to write, thus, there was not much to gain by using a better language.
3. The compiler seems to be rarely used on 8-bit AVR-s.

IMHO some of the features of C++ simply do not add any value for smaller code bases (for example, namespaces); others can be done away with little work (for example, references).

There is a tipping point in code base size after which the extra features of C++ are worth using or at least worth considering. It is somewhere in the range of 5 ... 50 KLOC, depending on circumstances. Let me note that 1 KLOC of C code compiles to about 3 kilobytes of binary code.

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

What's a Line Of Code? Is an opening brace a line of code? I guess comments don't count?

Imagecraft compiler user

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

clawson wrote:
I cannot think of anything worse than not having all the variables defined at the very top of a statement block. Who in the world ever thought there'd be an advantage to mixing them in the middle? When you see a segment of code with 'foo' being used your natural reaction is to look back first to the start of that block, then the start of the function then the start of the file to find the variable definition. Allowing them to be mixed into the code just obfuscates it. I suppose people will say that with modern source browning editors it doesn't matter because the editor will show the type definition wherever it's located but you aren't always using such an editor when looking at code.

Have to admit, your arguments are convincing. Perhaps I should try using this style.

I am not using such an editor, however, I do use local variable definitions all the time. Since at the moment there is nobody reviewing my code, the rationale behind it might be weak. I use this style because most of the time definition look-ups can be avoided since variables are next to the code using them. Code obfuscation can be mitigated by leaving some space between groups consisting of variable definitions and code blocks. For example:

	int	var1;
	int	var2;
	// code using var1, var2.

	int	var3;
	int	var4;
	// code using var3, var4 - and most probably var1 or var2, too.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
What's a Line Of Code? Is an opening brace a line of code? I guess comments don't count?

I count all the lines, regardless of type. Have never bothered to distinguish between them, since LOC is a rather lax metric anyway.

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

andreie wrote:

Have to admit, your arguments are convincing. Perhaps I should try using this style.

I am not using such an editor, however, I do use local variable definitions all the time. Since at the moment there is nobody reviewing my code, the rationale behind it might be weak. I use this style because most of the time definition look-ups can be avoided since variables are next to the code using them. Code obfuscation can be mitigated by leaving some space between groups consisting of variable definitions and code blocks. For example:

	int	var1;
	int	var2;
	// code using var1, var2.

	int	var3;
	int	var4;
	// code using var3, var4 - and most probably var1 or var2, too.

If I understood correclty, a better example is a for loop. Instead of declaring the loop counter far away from where it is used, you can declare it inside the for and it will exist only inside the for loop.

for(int i = 0; i < 100; i++) {
   do something with "i"
}

Felipe Maimon

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

clawson wrote:
I cannot think of anything worse than not having all the variables defined at the very top of a statement block.
Prior to learning C++, I would have agreed with you. The problem is that with objects you sometimes need to specify parameters when the object is created (instantiated in O-O speak) and some of those parameters may need to be computed by calling other functions. Allowing an object to be instantiated at/near the point of first use allows the other computing to be done first.

Of course, in many cases you can design your objects so that they don't need any parameters (or just constant parameters) when they're instantiated. In that case, you're perfectly free to define all of your variables at the top of a block as you prefer.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

something I wrote apparently in 2004 for my personal website
------------------------------------------------------
I had mainly written in C for many years, but a long time ago, did a
bit on C++ which eventually made me realise that some features of
C++ especially the operator stuff was a waste of time and merely
confusing (or at least to me). This feeling was re-inforced when I
spent a year or two writing in Java ... what a sweet language ...
clean, simple and makes me think the design thru. Going back to C++
after that was a culture shock. I currently write C++ in a style
that is as close to java as I can ... I like the concept of
interfaces and of inner classes (hiding info). I thought of
standardising my coding in java, but when I looked gcj didnt handle
inner classes , and combined with the fact that java wasnt free (as
in beer) , I decided to go back to C++ .
----------------------------------------------------

have not seen java for ages let alone written any ... C++ these days (on the PC).
When came back to electronics and started to look at micros , I chose the avr and naturally the
gnu compiler collection ie gcc or g++ .

Java wasnt perfect , and compiler/language systems that do stuff under the cover are things I didnt like
on the PC and even less so on a micro (automatic garbage collection, jit compiling , references etc).

The big item that I liked about java was that you could define an interface and have classes that
implemented that interface . I found that especially useful and altho C++ doesnt have directly the
interface concept, it can be done something like . Iirc, the interface is defined with no code in it .
The other item that java had was inner classes which I consider a very useful concept (found out later that C++ has them as well) .

For the PC I use C++ for my projects , and have tried and now use it on the atmega - atm with m328
but about to move to a mega324 for the extra pins for my particular project that I am working on .

So some thoughts on C++ esp from the micro pov .
(It is a long time since I thought about how to use C++ rather than just using it)

- classes are structs which can can have private data (and functions) ie which can not be accessed by
another class unless it is a 'friend' of it.I'm not convinced that is actually useful to prevent
another object 'stealing' data , but it is a useful concept that the data (and fns)
is not meant to be visible (to other classes)
ie there is a public set of functions that in a simple sense define the interface to that object.

- classes have functions (and so can structs) and one useful one is the constructor (ctor) which is called
whenever an object is createdand it initialises it .
There can be different ctors for a class each with its own list of parameters (which can be useful).
There is also a destructor function (dtor) which can be defined for any class , and would then be called
when it is destroyed .

- C++ has references , which some people like, but me, I like pointers because I know what is happening .

- C++ has a default copy constructor which allows it to create a copy of an object whenever it needs to ....
useful ? not normally .If an object is passed as a parameter, the compiler creates a copy of the object
on the stack and obviously it is destroyed on return.This happens if use a reference to an object
and pass that to a function .... which is one reason why I dont use references (if possible).

- On the pc , templates are a brilliant concept and there is a whole collection of maps,vectors,lists
sets etc and iterators to run thru them (these unfortunately use references and so I have to accept that).
No more writing yet another linked list or vector or ... with the standard template library you
can use code that is guaranteed to work efficiently (on any type of object) . This is on the PC I'm talking.

- the other big item is the ability to derive classes from a base class. Virtual fns often feature in this
and it allows the same function to be called for different objects.
It is possible to derive a class from more than one base class but that way generally lies madness .

- in C , a major concept is the callback function (with specific parameters) that is given to an
object , or passed in a function and when something happens or on completion, that callback function
is invoked with the appropriate params . Many things can be done with a simple knock()
function , which notifies the originator , and it can then interrogate whatever and get more details.
Obviously these are still available in C++ but maybe the C++ version is a client object with a
specific interface (ie is derived from the interface base class) which has a specific set of functions .
So one object can take a pointer to a client and when needed it can invoke the particular function of
that object frex:

struct  NotifyLinkState {   // in essence an interface definition
      virtual   void  notifyPaused( bool pause) = NULL  ; // pure virtual
      virtual   void  notifyLinkState( uchar enumstate) = NULL  ;
};
// cant remember why now but is better to have an empty rather than a pure
// virtual for a micro ....  ie replace the '= NULL' with '{ }'

struct   MyAppn  {

struct   MyLinkStateClient : public NotifyLinkState { // prvt inner class
        MyAppn  * mOwner ;

   void notifyPaused( bool pause) {
        mOwner->prvtNotifyPaused(pause);
   }
   void notifyLinkState( uchar enumstate) {
        mOwner->prvtNotifyLinkState(enumstate);
   }
};
       ...............
       void  prvtNotifyPaused( bool pause);
       void  prvtNotifyLinkState(uchar enumstate);

        Link     mLink ;
        MyLinkStateClient  mLSClient ;

       MyAppn( int baud)  : mLink(baud) , mLSClient(this)  {
           mLink.setStateClient(&mLSClient) ; // Link is assumed defined
                                              // before this
       }
       etc


this may look long winded , but one question you have to ask yourself in the initial design is whether
MyAppn is a NotifyLinkState object or not . It could be if there were only one link , but if have
several (eg xmegas) then it seems better to me to have multiple clients, one for each link.
It also seems cleaner to me to say the MyAppn is not a link state client, but to privately supply
one ... and I like cleanliness :-)

Let me try again here ... a complex object (COXX), might need info from several other objects ,
that each accept clients with a particular interface (eg the NotifyLinkState above) so it could
need several different clients for the different objects .... but if these were *all*
different , then the COXX *could* be derived from each of these items and be inserted as a client
into each . This obscures whatever the primary function of the object (COXX) and it is cleaner
to use inner classes which are instantiated in the COXX ctor .

- in my current avr project , there is a SysManager class which holds as member objects , all the
items I need , so an ECManager to hold the ECs , atm one link , one UCPManager to manage the UCPs,
an ADCController to handle adc jobs , a TimerQueue which uses T1 to initiate jobs at a particular
time in the cycle etc etc . There is a singleton of the sysmanager , defined in SysManager.h as
extern SysManager sSysManager ;
which allows access to all the objects to all the other objects and even to isrs , which is useful
for setting work flags.
The sysmanager also initialises the objects and the ports etc and then enters the main event loop .
accessing any object would look like

    sSysManger.mLink.sendPacket(&mypacket);  // this should be reduced
                                             // to an address at the load time
                                             // so minimal overhead


Another concept is that all the primary objects are ctor'd at one time (in the SysManager ctor) and
then some function doInit (not virtual) or whatever is then called on each and that cross stitches
them ie they insert their clients into the other objects (after they have been initialised) and then
the sei() is called and the system lets rip.

I have done some rs232 link code which uses the same base code for the avr and the pc , despite the
obvious differences .I would like to say I did it by careful design, but I actually coded
for the pc first (iirc) and then mangled it for the avr , and mangled the code into a base set ,
and two derived classes .So this allowed me to debug most of it on the pc and then try to get it
working on the avr . It still has some intermittent bugs which I WILL track down when they become
my top priority.

It was an interesting exercise and convinced me that I could use the OO approach on the avr
(not on the tiny) but nothing is dynamically allocated , all instantiated statically .

So probably things missing (from this list) but C++ stuff I dont use (on the avr) are :
- copy ctors
- references
- templates
- malloc,free,new,delete
- operator overloading

stuff I do use are
- interface definitions
- inner classes
- virtual fns

When I did the java programming , it encouraged me to look more into the whole OO stuff and after
that I found the Design Patterns book interesting, despite Johann's desire to avoid mention of them .

sorry this was a bit long winded , I hope it may be of interest.
One warning , tis ages since I learnt this stuff and I bailed out (retired) some time ago so
might be a bit out of touch with the latest wizz bang theories and/or practices (and I may have
become a bit set in my preferences :-) ).

If people are interested , I could clean up the link code and up load it as an example of how
I did C++ on a mega (not saying it is perfect but I am ok with it).

Cheers,

JoeSoap

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

JoeSoap wrote:
- C++ has references , which some people like, but me, I like pointers because I know what is happening .
Me too. I've never had any problems with pointers. Pointers are my friends. My secret is to distinguish pointers from all other objects by their names. I ALWAYS put "_p" at the end of a pointer name. Some people put the "p" at the beginning.

On the other hand, maybe I'm too stupid to understand references, or just too lazy to figure them out.

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

What's to figure out? It IS a reference. :wink:

Seriously, I find it interesting that one needs to "know what they really are" - beyond "they are addresses or akin to pointers if you like, but you don't need an explicit de-reference at every point of access".

This seems to me to be the usual "I don't like to relinquish control to the compiler" that I sort of accused the asm'ers of in the asm-to-C thread.

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

JoeSoap wrote:

- classes are structs which can can have private data (and functions)
Just to be clear, C++ classes are C structs which can have ....

In C++, classes and structs are identical, except class members are private by default and struct members are public by default. By using "public:" and "private:" they behave identically.

So why two names for the same thing? Just to confuse C programmers? :)

I guess "struct" conjures up thoughts of the layout of data in memory, and "class" conjures up thoughts of modularity.

By the way, there is one problem with C++ that C doesn't have. When writing C++, you have to think before you program. Think about what classes you want, that is. The advantage of C is you don't have to think, just start programming. :)

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

Johan

Quote:

Seriously, I find it interesting that one needs to "know what they really are" - beyond "they are addresses or akin to pointers if you like, but you don't need an explicit de-reference at every point of access".

This seems to me to be the usual "I don't like to relinquish control to the compiler" that I sort of accused the asm'ers of in the asm-to-C thread.

think that in C you know what you are using - the main exception
that comes to mind is the sizeof data . So there are pointers and data
and you know what to expect ... with references , you can end up
with a copy construction of what could be a large object , so I prefer
to use pointers , where what you see is what you get ... pass a pointer
as a parameter , only the space for a pointer is used, and no ctors called
etc , and the fn can use it to access the data .

That reminds me -C++ exceptions are another thing I wouldnt use in an avr
and dont in PC C++ . From memory, the java exceptions where simpler and cleaner .

steve17

Quote:

In C++, classes and structs are identical, except class members are private by default and struct members are public by default. By using "public:" and "private:" they behave identically.

So why two names for the same thing? Just to confuse C programmers? Smile

steve17 - thanks for clarifying the structs vs classes , when writing something
you are to close to see the way it can be read by other people ... I normally
leave for another day and go back to it ... leads to very slow writing .

Apologies for the poor formatting of the previous post ,
I spent ages copying it para by para from my editor into the entry form
and then hitting the preview button to check ... and when all was ok it
shows it in a narrower page width than the preview page ... grrrr

JoeSoap

Pages