What Makes C++ "Hard"?

Go To Last Post
186 posts / 0 new

Pages

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

Witness the number of beginners here trying to start out on a USB project ...

 And I still consider TWI as "advanced"!

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

KIIV_cz wrote:

What makes C++ so difficult (at least for beginers)? According to the Kate Gregory, it's C. If you start teaching some 5days introduction into the C++, whenever you mention pointers, index operator and so on, you have to take a looooong introduction into the C part of C++. And understanding pointers is not so easy.

 

Hah!  Understanding pointers is easy.  they are simply 24 bit ints with a bunch of flags for a total of 32 bits :>} The problem started when the managers and others started stating pointers are not ints.  Well technically they are unsigned 32 bit longs.  On some architectures the address registers were only 16 bits so pointers were 16 bits.   Now a days there are 64 bit pointers, although I doubt anything as that much dynamically addressable address space.

 

Typically a pointer points to an 8 bit "value" often called char in C.  This makes it easy to manipulate strings as there is a one to one mapping between an array of chars [] and a *char.

 

In the old days you just added one to a pointer to move the index.  Or subtract one to move it back.  Most people who were programming C learned ASM first.  This is the way ASM works.

 

As things got more complex one wanted to point to say 16 bit quantities rather than text quantities or more often to floating point structures.  in this case a 16 bit number is an array of size 2 or char int[2];  Now we have a new type called int which represents a number.   The confusion happens because a pointer (the 24 bits plus flags) *char only knows how to address the first 8 bits.   The construct *int knows that the value is 16 bits  so that char++ adds 1 to the pointer (ignoring the flags) and int++ adds 2 to the pointer.

 

As it is hard to remember how much gets added to the pointer,  C compilers maintain an internal identifier called size_t which tells the compiler how to map pointers to to address registers.   At this point thing could not be simpler.   Works the same as ASM.

 

Where things get more abstract (but are still simple.) is when blocks of memory contain a lot of different data.   C calls this a structure.  Now the compiler needs to know two things,  the offsets inside the structure and the size  of the structure.  AVR ASM has this built in as there are index registers which can offset by a simple number.  If for example a structure is a mailing address, such as name, street, city  then  theses become simple numbers that get added to the base pointer.  Adding the size_t of the record to the pointer advances one record, keeping the entry the same.  It is quite simple, but it is an unbounded infinity as records can contain other records or pointers to other records or sections of executable code.

 

Note that I left out type casting and memory management. These are implied in the pointer.  What the flags bits are for in the pointer.  These are hidden from the user and dependent on the implementation.   Dynamic memory allocation is a subject in and of itself as memory chuncks can be locked, relocatable, on the stack etc.  

 

With ASM and C one can have weak type casting as a pointer can point to anything in the memory space including code.   C++ is just a way to structure these allocations so that one does not have to keep a table of index offsets in ones head.   Sadly they got it too abstract.  Had they stuck with object structures, it would be fine.  Operator overloading, name spaces and that funny stuff with redirected IO instead of calling functions is where things get messy and the arguments get circular as are such concepts advanced features? or a simpler way to learn to "code."

 

 

 

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

There is a discussion going on on LinkedIn at the moment (https://www.linkedin.com/groups/... )

 

Here's one of the more interesting comments (from someone who seems to have a lot of strong opinions on the matter.)

 

Matt Heck: For microcontrollers _specifically_, as opposed to general embedded systems, I recommend C++ but without template usage. This is traditionally known as "C with classes", and the academics and architecture astronauts will roll their eyes at it. IGNORE THEM. This is an EXTREMELY effective approach for developing reusable, maintainable, extensible, _debuggable_ code for compact targets.

 

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

So, can I ask incredibly noobish question about C++ here? I'm trying to learn it to, but just in very mild doses.

 

For example, this operator overload stuff is quite interesting. Here is some code:

 

#define OP <<

typedef struct {
	char a;
	char b;
} pair;

void operator OP (pair &l_arg, const int &r_arg) {
	l_arg.a = (char) r_arg;
	l_arg.b = (char) r_arg;
}
int main() {
	pair test;
	test OP 2;
	return test.b + test.a;
}

 

So, this struct has a pair of chars, and with the overloading, I can use any operator do to whatever, in this case load both char with the same value. Neat. Problem, is, it doesn't work with the "=" operator, why? Compiler complains that it must be a "nonstatic member function". Needs to be inside a class, I suppose, but why?

I didn't want to use classes yet, just graft some useful C++ stuff into plain C.

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

clawson wrote:

awneil wrote:

(go on - who had to look up "trigraph" and/or "ternary operator"

 

Presumably those who haven't been doing C for 10+ years? ;-)

 

I guess a more pertinent question is "go on - who has ever actually USED trigraphs"?

 

(I'm pretty sure we all use ternary and probably quite regularly).

 

BTW my understanding of trigraphs was that they were for those who had limited keyboards without all the punctuation symbols - surely, since IBM AT (1986 was it?) and the 105/106 key keyboard that has not been the case for a VERY long time.

 

I have used trigraphs in the 90's , when doing C on an IBM Mainframe running MVS.

And the DK version of a 3270 EBCDIC keyboard didn't have ie. {} or []

 

/Bingo

Last Edited: Tue. Jul 11, 2017 - 04:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

@El Tangas: You already are using classes (in disguise). In C++ structs and classes are the same (except for a minute detail).

 

I'm not sure why you chose to overload <<, and then hide that behind a macro "OP"?

 

What you are doing is an assignment, so why not overload the natural choice of operator (i.e. =)? So (sketchy, untested!):

 

class Pair {
public:
  // Some constructors will come in handy..
  Pair()
    : a(' '), b(' ')
    {}

  Pair(char a, char b)
    : a(a), b(b)
    {}

  // Here's the operator overloading!
  Pair & operator = (const Pair & source) {
    a = source.a;
    b = source.b;

    return *this;
  }

private:
  char a;
  char b;
};

Usage:

  Pair p1('X', 'Y');
  Pair p2;
  p2 = p1;

 

There might be hard "technical" reasons for the = (and <<) operator(s) to be class members but I don't know off hand of any such. But anyway it makes sense that in any case where an operator alters an object the operator is a member of the class. Just like a when function modifies some member variable value in a class that function should be a member of the class.  The term is "Encapsulation". Keep data and "procedure" together in one place, the outside world ignorant of how it is internally implemented. 

 

EDIT: In general, whe n objects become more than "trivial", it makes sense not to do a lot of copying when the user does something like

p1 = p1;

so..

  Pair & operator = (const Pair & source) {
    if (this == &source) {
        return *this;
    }

    a = source.a;
    b = source.b;

    return *this;
  }

I will not get surprised if someone chokes on those &'s and *'s   ;-) 

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. Jul 11, 2017 - 05:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Problem, is, it doesn't work with the "=" operator, why?

 

Sure it does, if you set it up right; it should only take one argument, and returns a result...

Here's a copy of one of the Arduino functions:

 

String & String::operator = (const String &rhs)
{
	if (this == &rhs) return *this;
	if (rhs.buffer) copy(rhs.buffer, rhs.len);
	else invalidate();
	return *this;
}

(ooh.  This is the kind of thing that needs to go in a cheat sheet...)

 

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

westfw wrote:

El Tangas wrote:
Problem, is, it doesn't work with the "=" operator, why?

  Sure it does,

I believe what El Tangas is trying to say is "problem is, it does not work outside a class". (And no, it does not.)

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

BTW, the operator overloading I did above does the same things that the compiler would provide in the default version - just so no-one gets stuck wondering what it "contributes".

 

Also, the technically correct term is "the copy assignment operator". When you do overload of that you should overload the copy-constructor at the same time. The copy constructor is used e.g. here

 

Pair p1('X', 'Y');
Pair p2(p1);  // <-Copy cunstructor gets called here!

An implementation of the copy constructor corresponding to the copy assignment operator in #57 would go:

 

class Pair {
   .
   .
   .
   Pair( const Pair & source) {
       a = source.a;
       b = source.b;
   }
   
   // ... or, using the initializer list instead:
   Pair( const Pair & source)
     : a(source.a), b(source.b)
     {}
   
   .
   .
   .
}

No need to check for self-assignment in the copy-constructor, since you (of course) aren't allowed allowed to

 

Pair p3(p3);

 

And as for the copy assignment operator, the copy constructor implementation above is what the compiler supplies as default.

 

More on both copy constructor and assignment operator here: http://www.cplusplus.com/article...

 

 

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

Thanks guys, since I know so little of C++, it will take a while to analyze your posts... Probably I will have more questions latter.

 

Edit:

JohanEkdahl wrote:
I'm not sure why you chose to overload <<, and then hide that behind a macro "OP"?

Oh, this was just to test a bunch of operators with a bit less typing. When I tried "=" it gave that error I mentioned, I didn't even notice the "=" operator has just one argument. Why is that anyway, if "=" has 2 sides, source and destination?

Last Edited: Tue. Jul 11, 2017 - 10:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

1. Seasoned programmers admitting that they have "trouble" with some of the features. That makes it much easier for us mortals who struggle with even the basics.

Oh, I've seen many professional programmers struggle even with C. I mean basic stuff, like pointers.

 

e.g A colleague was sure there was a compiler error, because his function returned false even when the strings were the same:

 

bool test_string(char *str1, char *str2)
{
  if (str1 == str2)
    return true;
  else
    return false;
}

 

After I explained about pointers, he said he was sure that was not the problem, because he tested it and it worked. His test was :

 

  if (test_string("fred", "fred"))
    DEBUG_PRINT ("same\n");
  else
    DEBUG_PRINT ("different\n");

That may well return true, because the compiler puts identical strings into a common pool, so they have the same address. After all that, he seemed to accept my explanation, but offered the excuse "I've never really used strings before". That is what I would consider totally basic stuff for a professional C programmer. Now imagine how he got on with C++ ...

 

Complexity is quite hard to define, but a rule of thumb might be:  "number of ways unique elements can be combined." In the worst case, that is N ^ 2 where N is number of unique elements (assuming all elements can be combined with any other).

 

Another dimension is levels of abstraction, which is even harder to define. It is very dependent on the individual, some will say abstraction makes things simpler, because the same abstraction can apply to many instances, others say it just makes things harder to understand, because it moves one step away from the details. Levels of abstraction is similar to "algorithmic complexity". E.g. the sequence (0,1,4,9,16,25,36,...) can be expressed simply as n^2, where n is Positive integer. n^2 is more compact, so could be considered "simpler",  but you need to understand the abstraction.

 

C++ contains more language elements, has more ways to combine them, and introduces several new levels of abstraction. By that measure, it is certainly more "complex" than C. Whether that complexity is easy to understand or not, really depends on the programmer.

 

Bob. Engineer and trainee Rocket Scientist.

Last Edited: Tue. Jul 11, 2017 - 11:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

donotdespisethesnake wrote:
C++ contains more language elements, has more ways to combine them, and introduces several new levels of abstraction. By that measure, it is certainly more "complex" than C.

I really like that way of looking at it!

 

One remedy to complexity is what is sometimes called "orthogonality (of the language, in the broad sense)". I.e. patterns (oops, dangerous term, not intending "Design Patterns" here) are the same. It's when you can go "Well, if it worked that way there, then I suppose it should be this way here". E.g. see my figure above comparing a simple integer-indexing loop with one using an iterator.

 

Once you "break through", there is quite a lot of orthogonality in C++.

 

Before you "break through", it's another story..

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

In my research on C++ references, I learned that this allows assigning values to function calls. I find this very interesting, it's like you can use the compiler as a kind of macro preprocessor (I hope this simplistic comparison doesn't offend C++ experts...).

 

So here is a rather useless test program I wrote. But this certainly has potential even for MCU programming.

 

enum port_label {B, C, D};

volatile uint8_t & Port(port_label t){
	switch (t) {
		case B:
			return PORTB;
		case C:
			return PORTC;
		case D:
			return (volatile uint8_t &) PORTD;
	}
}

int main (void) {
	Port(B) = 0xFF;
	Port(C) = 0xFF;
	Port(D) = 0xFF;
}

This assembles to:

int main (void) {
        Port(B) = 0xFF;
  7a:   8f ef           ldi     r24, 0xFF       ; 255
  7c:   85 b9           out     0x05, r24       ; 5
        Port(C) = 0xFF;
  7e:   88 b9           out     0x08, r24       ; 8
        Port(D) = 0xFF;
  80:   8b b9           out     0x0b, r24       ; 11
}
  82:   80 e0           ldi     r24, 0x00       ; 0
  84:   90 e0           ldi     r25, 0x00       ; 0
  86:   08 95           ret

So this feature o C++, at least, doesn't seem to introduce any kind of special bloat.

 

Edit: there seems to be an implicit cast from type to type& in situations like this, I left it explicitly in the code for PORTD, so I don't get confused by this.

Last Edited: Tue. Jul 11, 2017 - 08:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
Edit: there seems to be an implicit cast from type to type&

Don't think of references as pointers. While there is a definitive type difference between

SomeClass anObject

and

SomeClass * anObjectPointer;

i.e. the anObject and the anObjectPointer is of distinctively different types, this is not true for references.

 

Think of references as alternative names (dare I use the term "alisases"?) for variables. So with

SomeClass anObject;
SomeClass & anObjectReference = anObject;

the anObject and anOBjectReference are of the same type.  This is also hinted at by the fact that access to members through anObjectReference is done the same way as through anObject:

 

  Pair p1('X', 'Y');

  Pair & p3 = p1;
  p3.a = 'Z';
  
  printf("%c\n", p1.a);  // Prints 'Z'

 

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. Jul 11, 2017 - 10:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So here is a rather useless test program I wrote. But this certainly has potential even for MCU programming.

But you can do almost the same thing in C, though it's somewhat uglier (but also less mysterious?)

enum port_label {B, C, D};

static inline volatile uint8_t * Port(enum port_label t){
	switch (t) {
		case B:
			return & PORTB;
		case C:
			return & PORTC;
		case D:
		    return (volatile uint8_t *) & PORTD;
	}
}

int main (void) {
	*Port(B) = 0xFF;
	*Port(C) = 0xFF;
	*Port(D) = 0xFF;
}

 

(I actually had quite a bit of this sort of problem.  People would enthusiastically point out some object-oriented THING you could do in C++, and I would be "but I'm already doing that in ordinary C; why do I need a new language?"  Of course, the C implementation was a bit weird, and typically hid some ugliness inside C macros, so arguably C++ did have advantages.  At the moment, people seem to be all excited about "lambdas", and I'm thinking "pointers to functions; big deal.  Except now you don't have to explicitly write the function you're pointing to.  Which is good because...  because ...  ??  Because the "obfuscated c++ contests" can get even more mysterious entries?")

 

 

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

Interesting, I had no idea you could do that in C blush

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

westfw wrote:
At the moment, people seem to be all excited about "lambdas", and I'm thinking "pointers to functions; big deal.  Except now you don't have to explicitly write the function you're pointing to.  Which is good because...  because ...  ??  Because the "obfuscated c++ contests" can get even more mysterious entries?")

Because lambdas have access to all of the containing function's variables, so you don't have to pass them to the function as arguments (which can be unwieldy if the lambda needs access to a lot of the parent function's variables). It's unfortunate that C++ doesn't support closures, though, because those are really cool.

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

Has anyone tried an "Obfuscated C++" competition, or would that just be a little bit too rude?  S.

 

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

westfw wrote:
People would enthusiastically point out some object-oriented THING you could do in C++, and I would be "but I'm already doing that in ordinary C

People often don't understand (or overlook) the difference between an object-oriented approach to design/programming (which you can do in 'C'), and having an actual object-oriented language (like C++).

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

 case D: return (volatile uint8_t *) & PORTD;

I'll bite - why is the D case different to B and C ?

 

Oh and back at:

int main (void) {
	Port(B) = 0xFF;
	Port(C) = 0xFF;
	Port(D) = 0xFF;
}

Mt main question here would be "why?". Why not simply write:

int main (void) {
	PORTB = 0xFF;
	PORTC = 0xFF;
	PORTD = 0xFF;
}

or is this so you can:

int main (void) {
	Port(rand() % 2) = 0xFF;
}

or something ?

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

clawson wrote:

or is this so you can:

int main (void) {
	Port(rand() % 2) = 0xFF;
}

or something ?

 

I'm just testing possibilities, stuff that could be hypothetically done with the languages, since I want to know more about C++ and C. What you wrote would be an example.

 

clawson wrote:
I'll bite - why is the D case different to B and C ?

 

This one will require more explaining. Recalling the C++ code:

volatile uint8_t & Port(port_label t){
	switch (t) {
		case B:
			return PORTB;
		case C:
			return PORTC;
		case D:
			return (volatile uint8_t &) PORTD;
	}
}

As you know, PORTx are of type (volatile uint8_t), while the function returns (volatile uint8_t &). In my opinion, C++ is doing a cast implicitly here. I made it explicit in the last option just as a reminder.

 

In the C equivalent, it's different:

 

static inline volatile uint8_t * Port(enum port_label t){
	switch (t) {
		case B:
			return & PORTB;
		case C:
			return & PORTC;
		case D:
		    return (volatile uint8_t *) & PORTD;
	}
}

That is, &PORTx are already of type (volatile uint8_t *), so nothing is happening behind our backs.

Now, for the part I have doubts. In , Johan said:

 

JohanEkdahl wrote:

Think of references as alternative names (dare I use the term "alisases"?) for variables. So with

SomeClass anObject;
SomeClass & anObjectReference = anObject;

the anObject and anOBjectReference are of the same type. 

 

However, check this program:

typedef struct {
	char a;
	char b;
} Pair;

uint16_t & Set(Pair *p){
	return (uint16_t &) *p;		//OK
	//return (uint16_t) *p;		//Not OK	
}

int main (void) {
	Pair test;
	Set(&test) = 0x1020;
	return test.b;  //Will return MSB (0x10)
}

The commented out line can not be used, therefore  the types (uint16_t) and (uint16_t &) are different. Right? Just asking.

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

El Tangas wrote:
The commented out line can not be used, therefore  the types (uint16_t) and (uint16_t &) are different. Right? Just asking.

Possibly. Need to check. Will be back..

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

After a very quick read of some content on The InterWeb, it seems that references are (at least in a technical/theoretical sense) of different a different type than the variable it references.

 

But, as far as I know, for all practical purposes you don't need to typecast. As in my example earlier there is no need to typecast to do

 

SomeClass anObject;
SomeClass & anObjectReference = anObject;

A common explanation of what references are is "alternate name" or "alias" (the latter being somewhat dangerous to use without being very clear about it, since "aliasing" is a term that has another meaning and other implications).

 

Will look around a little more to see if there are any "complications" when using aliases in type hierarchies.

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 don't have time right now to read all the responses so I might be duplicating.

 

I've been writing C/C++ for well since '95 so 22 years, programming for that + 10 or so

Is C++ hard? Well it has a lot of depth.

 

Dancing is a hobby of mine, the waltz is a simple dance, but it has incredible depth.

I can teach you the basics in an hour. You'll never learn it all.

 

C++ is the same.

At the shallow end it's basically C with better type checking.

At the deep end it's templates and objects and huge libraries.

 

Libraries are far more complicated than any mere language, when you add MFC, STL, Net, Linq etc you are out of the C++ world and into the library support. Don't blame the language for that

 

The one place where C++ has real issues is interfacing to C. especially callbacks / function pointers. There's just no clean way to handle a function pointer in C++.

if you are in PURE C++ you can do things that work, but if you call a C lib that wants a callback, it gets messy fast.

 

 

My latest project is 100% c++, all the interrupts, event driven state machines, serial IO, all C++. All written from scratch :P

FWIW, the coolest use of C++ I've seen is a templated ring buffer. it can take any type, builtin or custom with zero coding.

Works every damn time.

You want a uint8_t ring buffer, 1 line of code to create it

You want a ring buffer that takes your custom objects, again, 1 line of code. poof done.

 

Another great thing about C++ is data hiding, all you private data is private, the outside world doesn't even see it. No more structs being passed around and getting corrupted by jimmy the intern ( Peter the principal engineer)

 

C++ is not too hard, you're too weak.

 

Keith the Klingon programmer

"You have insulted my code. Prepare to die"

 

Keith Vasilakes

Firmware engineer

Minnesota

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

 

He hasn't taken the red pill yet, hes still in the C Matrix.

Templates do not, on their own, cause problems. People misusing templates cause problems.

 

westfw wrote:

There is a discussion going on on LinkedIn at the moment (https://www.linkedin.com/groups/... )

 

Here's one of the more interesting comments (from someone who seems to have a lot of strong opinions on the matter.)

 

Matt Heck: For microcontrollers _specifically_, as opposed to general embedded systems, I recommend C++ but without template usage. This is traditionally known as "C with classes", and the academics and architecture astronauts will roll their eyes at it. IGNORE THEM. This is an EXTREMELY effective approach for developing reusable, maintainable, extensible, _debuggable_ code for compact targets.

 

Keith Vasilakes

Firmware engineer

Minnesota

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

Keith how ate you doing interrupts in C++. Presumably ditching the ISR() mechanism the CRT provides?
.
The issue is that very thing you mention - trying to get a pointer to a function "inside" a class (so it kind of has to be static )

Last Edited: Wed. Jul 12, 2017 - 06:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

keith v wrote:

FWIW, the coolest use of C++ I've seen is a templated ring buffer. it can take any type, builtin or custom with zero coding.

Works every damn time.

You want a uint8_t ring buffer, 1 line of code to create it

You want a ring buffer that takes your custom objects, again, 1 line of code. poof done.

Yup. I used that as an example just the other day. In another thread - so re duplicating, as far as I'm concerned you're off the hook..

keith v wrote:
Dancing is a hobby of mine, the waltz is a simple dance, but it has incredible depth. I can teach you the basics in an hour.

No, you can't. But that's not your fault..

 

I'm not pleased with Matt Heck's categorical comment about templates. The example just given, the circular/ring buffer, is an excellent example on how generics are much easier  and clearer in C++ than in C. Also, for some cases, it makes perfect sense to utilize some of STL. It's the same old story, again.. Use things blindly. Fail. Have insight. Succeed.

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

clawson wrote:
Keith how ate you doing interrupts in C++. Presumably ditching the ISR() mechanism the CRT provides? . The issue is that very thing you mention - trying to get a pointer to a function "inside" a class (so it kind of has to be static )

 

Clint

Yeah, thats one ugly part.

I basically poll the I/O

Luckily I/O is usually pretty slow

 

If you _need_ a callback, due to tight timing, you need a static member variable that points to the class instance.

Set the instance to yourself on construction

Then IRQ, which is a static function, then uses the static instance variable to call into the non static class.

Doable but ick.

 

It's also possible sometimes to make the whole class static, but thats a mess of a different color.

 

 

Keith Vasilakes

Firmware engineer

Minnesota

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

keith v wrote:
My latest project is 100% c++, all the interrupts [...] all C++.

 

clawson wrote:
The issue is that very thing you mention - trying to get a pointer to a function "inside" a class (so it kind of has to be static )

 

As far as I know and understand it has to be static. Can't see how hardware and "vectoring" can know which object instance to use for the this-pointer.

 

Also, as long as we're talking avr-gcc/avr-g++/avrlibc, I have assumed the ISR needs to have "C linkage" rather than "C++ linkage". I suppose this could be changed by one supplying new/altered startup code, though.

 

@keith v: If you have a technique outside of what me and Cliff just said, we'd  be genuinely interested in being taught it! ISRs in C++ (avr-g++) is one of the things many newcomers to the AVR and C++ combo ask about. (Just to be clear: Do not misunderstand this! I'm not picking a fight or some such! I'm genuinely interested if you know something I/we don't!)

 

keith v wrote:
C++ is not too hard, you're too weak.

LOL! Literally!

 

To play along with your SF wordplays: ALL THESE LANGUAGE FEATURES ARE YOURS, EXCEPT TEMPLATE META PROGRAMMING. ATTEMPT NO USAGE OF THAT.

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 guess I kinda exaggerated, the interrupt handlers are in c++ but they are static, the actual ISR is a non member function so GCC knows what to do.

You guys do sound like you know whats going on C++ wise, and I know you know you c AVR stuff.  We definitely arent arguing.

 

I still like C++, and will continue to use it when I can. I mean the warts on C are way way bigger IMHO.

 

I dont know who Matt Heck is, but I do know Micheal Barr likes C++

Keith Vasilakes

Firmware engineer

Minnesota

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

There are a couple of things that are particularly off-putting to a C/asm programmer when a C++ programmer tries to wax poetic on its virtues...

 

  1. "It has this important feature." (describing some feature that your C compiler has had for decades, like "inline", or "const can replace #define", or "better type checking than pre-prototype C functions.")
  2. "<really expensive feature> is very powerful!" - like STL, or like using exceptions instead of explicit parameter verification.
  3. "You don't really need <important feature> because you can do <expensive alternative>", rather like:

I basically poll the I/O [instead of being able to handle interrupts properly]

 

Templates do not, on their own, cause problems.

 That's what I thought...  Do C++ programmers regularly say "templates" when what they mean is "The Standard Template Library" ?  The STL certainly seems to be a set of lovely functions generalized with dynamic allocation and exception handling to the point where you would have to do a lot of work to make it work well on a deeply embedded system.  But I don't see any reason why templates (or even TMP) in general can't be used to implement useful microcontroller-based things (though, come to think of it, "real C++ programmers" might Frown Mightily at such code.)

 

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

One thing I find off-putting about OOP on an AVR is the fundamental architecture.

 

An 'Object' contains both data (attributes) and code (procedures) all in one lump.  An object-oriented program is then constructed out of many of these lumps.

 

This is in complete contravention of the AVR's Harvard architecture, where the data lives over there (in the SRAM or EEPROM) and the code lives over here (in the flash).* 

 

It probably makes a lot more sense on a PC, where everything's in RAM.  Of course, that causes all sorts of fun stuff when your data starts to overwrite your code.  AVRs don't do that.**

 

S.

 

* Generally speaking.  I know you can put static data in the flash, and execute code from SRAM via a bootloader (through writing it into flash), et cetera, but the concept still holds.

** Unless you have a lot of SPM instructions lying around for writing self-modifying code, in which case may your Lord have mercy upon your soul.  Or a screwed-up bootloader.

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

Scroungre wrote:
One thing I find off-putting about OOP on an AVR is the fundamental architecture.

 

An 'Object' contains both data (attributes) and code (procedures) all in one lump.  An object-oriented program is then constructed out of many of these lumps.

 

This is in complete contravention of the AVR's Harvard architecture, where the data lives over there (in the SRAM or EEPROM) and the code lives over here (in the flash).*

Not relevant.

OOP does not require copying code at runtime.

The code associated with an object is the code associated with its classes.

Virtual tables do not contain code.

They contain pointers to code.

Iluvatar is the better part of Valar.

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

Could someone explain me better what is the problem of ISRs in C++? (probably it will not be possible, since I don't know almost anything of OOP)

Is it because you want to put them inside a class? Does that even make sense? I mean, "main" and all initialization that comes before, are an ISR (Reset).

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

I think that would be better as a separate thread!

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:

One thing I find off-putting about OOP on an AVR is the fundamental architecture.

 

An 'Object' contains both data (attributes) and code (procedures) all in one lump.  An object-oriented program is then constructed out of many of these lumps.

 

This is in complete contravention of the AVR's Harvard architecture, where the data lives over there (in the SRAM or EEPROM) and the code lives over here (in the flash).*

 

On relevancy:

 

skeeve wrote:

Not relevant.

OOP does not require copying code at runtime.

The code associated with an object is the code associated with its classes.

Virtual tables do not contain code.

They contain pointers to code.

 

by line:

 

1) No, OOP does not require it.  But it is a feature of the language.

2) Um, yeah.  So?

3) & 4) Pointers are code.

 

There's a lot of good done with OOP.  Furthermore, the compilers cheerfully split it all up as they feel like, and I'm sure it does what it is supposed to do.  But I don't think much of it on an AVR.  My US$0.02

 

S.

 

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

JohanEkdahl wrote:
I suppose this could be changed by one supplying new/altered startup code, though.
Had the very same thought yesterday. For C++ instead of __vector_1, __vector_2 etc the weak linked jump destinations should be something like _Z8vector01v or whatever the mangled name for a void fn(void) happens to be. However they'd still be "classless" even if they had C++ linkage. But it just saves a little bit of extern "C" grief.
El Tangas wrote:
Is it because you want to put them inside a class? Does that even make sense?
The classic example (as shown by Arduino) is going to be something like a Serial/Uart class. You want to "connect" your RXC interrupt to a handler (probably a ring buffer stuffer) in the Uart/Serial class. As a typical AVR has from 1 to 8 (is it on Xmega?) UARTs you want to be able to write the class to cope with a "generic UART" then at instantiation you say "Uart Uart0(&UCSR0A, &UCSR0B, &UDR0 etc)". That instance will have the ring buffer for RXC on Uart0. Then you have instance "Uart Uart1(&UCSR1A, &UCSR1B, &UDR1...)" and so on. But somehow you have to map the fixed, C named UART0_RXC_vect (which is probably really __vector_17 or something) to the ring stuffer (oo, dreadful phrase!) in Uart0{} and UART1_RXC_vect (__vector_23 etc) to the ring stuffer in Uart1{} and so on.

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

Ah, ok I see the problem, thanks.

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

clawson wrote:

JohanEkdahl wrote:
I suppose this could be changed by one supplying new/altered startup code, though.
Had the very same thought yesterday. For C++ instead of __vector_1, __vector_2 etc the weak linked jump destinations should be something like _Z8vector01v or whatever the mangled name for a void fn(void) happens to be. However they'd still be "classless" even if they had C++ linkage. But it just saves a little bit of extern "C" grief.
El Tangas wrote:
Is it because you want to put them inside a class? Does that even make sense?
The classic example (as shown by Arduino) is going to be something like a Serial/Uart class. You want to "connect" your RXC interrupt to a handler (probably a ring buffer stuffer) in the Uart/Serial class. As a typical AVR has from 1 to 8 (is it on Xmega?) UARTs you want to be able to write the class to cope with a "generic UART" then at instantiation you say "Uart Uart0(&UCSR0A, &UCSR0B, &UDR0 etc)". That instance will have the ring buffer for RXC on Uart0. Then you have instance "Uart Uart1(&UCSR1A, &UCSR1B, &UDR1...)" and so on. But somehow you have to map the fixed, C named UART0_RXC_vect (which is probably really __vector_17 or something) to the ring stuffer (oo, dreadful phrase!) in Uart0{} and UART1_RXC_vect (__vector_23 etc) to the ring stuffer in Uart1{} and so on.

 

I don't see the C++ linkage as a problem, the IRQ is C but it can access a class instance just fine as long as there is a file global reference to it.

 

A better way to do that is to make 8 uart classes and then pass a ref to a serial class that then uses the uart. You'd also pass in you ring buffers and so on.

The serial class doesn't know about the uart hardware and the uarts are specific to the desired hardware allowing different uart setups per instance.

The uart class would also handle the ISRs

 

This also allows unit testing the serial class with a mock uart.

 

C and esp embedded programmers have a hard time with this because it looks like so much extra code. But it's not really. it's the same as in C just more organised.

Keith Vasilakes

Firmware engineer

Minnesota

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

clawson wrote:
30+ year old keyboards: from their original prototypes. (even if most of the labels are now worn off).

 

Never mind wearing the labels off - I seem to have worn a hole in the LH Shift key:

 

surprise

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
On relevancy:

 

skeeve wrote:

Not relevant.

OOP does not require copying code at runtime.

The code associated with an object is the code associated with its classes.

Virtual tables do not contain code.

They contain pointers to code.

 

by line:

 

1) No, OOP does not require it.  But it is a feature of the language.

2) Um, yeah.  So?

3) & 4) Pointers are code.

1) Not of C++.

2) In C++, though admittedly not Python, the classes and their code are fixed at startup.

3 & 4) Pointers are not code.  In an AVR, the IJMP and ICALL pointers are not in program memory.

Iluvatar is the better part of Valar.

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

clawson wrote:
Jan, BRILLIANT link! Says it all really. . Oh and I'm intrigued he recommends Python as a first language. Couldn't agree more. Wish it had been around when I started!
just fyi from another thread: I love you again now. Python is my lifeblood.

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

ka7ehk wrote:

Witness the number of beginners here trying to start out on a USB project ...

 And I still consider TWI as "advanced"!

 

Jim

 

That's because TWI/I2C is evil! I have some locking issues that I can only fix with some elaborate reset code. 

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

westfw wrote:

So here is a rather useless test program I wrote. But this certainly has potential even for MCU programming.

But you can do almost the same thing in C, though it's somewhat uglier (but also less mysterious?)

enum port_label {B, C, D};

static inline volatile uint8_t * Port(enum port_label t){
	switch (t) {
		case B:
			return & PORTB;
		case C:
			return & PORTC;
		case D:
		    return (volatile uint8_t *) & PORTD;
	}
}

int main (void) {
	*Port(B) = 0xFF;
	*Port(C) = 0xFF;
	*Port(D) = 0xFF;
}

 

(I actually had quite a bit of this sort of problem.  People would enthusiastically point out some object-oriented THING you could do in C++, and I would be "but I'm already doing that in ordinary C; why do I need a new language?"  Of course, the C implementation was a bit weird, and typically hid some ugliness inside C macros, so arguably C++ did have advantages.  At the moment, people seem to be all excited about "lambdas", and I'm thinking "pointers to functions; big deal.  Except now you don't have to explicitly write the function you're pointing to.  Which is good because...  because ...  ??  Because the "obfuscated c++ contests" can get even more mysterious entries?")

 

 

This exact reason is why I hate lambdas in Python, the language whose entire purpose is to be readable. 

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

Lambdas can make code clearer and easier to read. As always, if used "right".
.
Of-course, if you arent familiar with the syntax, or even the concept, they are obfuscated to you.
.
One way to think about lambdas are as anonymous functions written "in situ".

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 do use lambdas in my TKinter code, but much more rarely than most do. I know the syntax and concept. I just don't like it. However, in other languages I like them better. In Pyhton they bug me (especially when they're fed to filter or map when a list comprehension/generator would have been SO MUCH more idiomatic). The exampl of having access to the locals i a good one for C++, but I don't even think it's true for Python. 

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

I started writing a general piece on C++ lambdas for those not not familiar with the concept. It got so long that I realized that posting it here would be a serious derail of the thread so I posten in a new thread instead:

 

https://www.avrfreaks.net/forum/l...

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

Scroungre wrote:
One thing I find off-putting about OOP on an AVR is the fundamental architecture.   An 'Object' contains both data (attributes) and code (procedures) all in one lump.  An object-oriented program is then constructed out of many of these lumps.   This is in complete contravention of the AVR's Harvard architecture, where the data lives over there (in the SRAM or EEPROM) and the code lives over here (in the flash).*    It probably makes a lot more sense on a PC, where everything's in RAM.

IMO OO make a lot of sense on AVRs too.

 

I don't see OO as a way to reflect the low-level Harvard architecture idiosyncrasies at all. On the contrary, I see OO as a way to "abstract away" parts of that, and to combine hardware (as in e.g. IO modules), low-level software (as in reading/writing e.g. IO locations) and also adding functionality. All this to create an abstraction that makes sense on a higher level.

 

If I want buffered USART I/O with flow control I for an application then I can combine all that stuff into a class that has the interface something like:

 

 

class BufferedSerial {
public:
  boolean dataReady();
  char read();
  void write(char c);
  
private:
  ...
}

The part of the class that is private (or possibly protected) is all that goey stuff like looking accessing I/O registers, handling ring buffers etc. On the "application level" there is no need to see that stuff at all. The application level just want's to see what it really needs to see of that serial communications "module".

 

I can't understand why, at the application level, you'd need to "be aware" of e.g. that AVRs are Harvard.

 

The parallell to some stuff in the plain old avrlibc C runtime library is obvious. Specifically the stdio stuff. write a putc() and a getc(), set up the stdin and stdout file streams - and shuffle all that out of the way in a separate source file. Then, in main() use printf(). Everything re how and where your written data ends up is abstracted away from the "application level" and there is no reason to care at all that this executes on a Harvard architecture.

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

skeeve wrote:

3 & 4) Pointers are not code.  In an AVR, the IJMP and ICALL pointers are not in program memory.

 

Semantics, I guess.  What a pointer points at can be had from anywhere, but the fact that it is a pointer and should be treated as such counts as 'code'.  IMHO.

 

JohanEkdahl wrote:

I don't see OO as a way to reflect the low-level Harvard architecture idiosyncrasies at all. On the contrary, I see OO as a way to "abstract away" parts of that, and to combine hardware (as in e.g. IO modules), low-level software (as in reading/writing e.g. IO locations) and also adding functionality. All this to create an abstraction that makes sense on a higher level.

 

This, of course, being the whole point of abstraction.  In a way, AVRs themselves are highly abstracted - We're not doing the math on how much current is running through each transistor when we ask for, say, an 'add' instruction.

 

But sometimes it does matter.  Abstraction is one thing, but sometimes strange things can go wrong due to a misunderstanding of what's happening at a lower level, and fundamental comprehension of that is at least important, if not essential.  For example, your C++ code might be totally flawless, but if you're regularly asking for 50mA from an I/O pin, it's not going to work, because we can't completely abstract away just how much current is running (or trying to run) through a transistor.

 

I'm not saying OOP on AVR doesn't work.  I imagine it works fine.  It just bugs me. 

 

It also strikes me as a recipe for inefficiency, although I've never seen speed comparisons of half-decent C++ vs. C code on AVRs.  Depends a great deal upon the compiler, I would guess.  But if a C++ compiler has to work a lot harder to make code of similar speed and size, then the abstraction is not well-aligned to the hardware.

 

And one could also say that's irrelevant, because hardware is so cheap and so fast these days why bother writing efficient code?

 

S.

 

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

I don't think your I/O pin example works well. The problem would be the same with a C or assembler programmer not aware of the current limit.

If someone can't be bothered to read the datasheet and understand the hardware it's not the fault of the programming language they chose.  You could actually prevent this issue  in C with the preprocessor or templates in C++.

 

Using C++ isn't any more inefficient then using C. 

Now, using older AVR's does prevent you from being extremely efficient with C++, but it's a beautiful thing on Xmega's (The IO/memory map is laid out consistently).

Both C and C++ have a level of abstraction that can be difficult for the compiler programmers to deal with. In fact plenty of issues arise before even getting to the C/C++ level (gimple/bitcode).

 

 

Pages