I do not understnd this funcion, work, is ued by my loop, but i cannot understand the first part..
void colore(void *ptr) {
RGB *c;
c = (RGB *)ptr;
analogWrite(GREEN, 255-c->green);
analogWrite(BLUE, 255-c->blue);
analogWrite(RED, 255-c->red);
I do not understnd this funcion, work, is ued by my loop, but i cannot understand the first part..
void colore(void *ptr) {
RGB *c;
c = (RGB *)ptr;
analogWrite(GREEN, 255-c->green);
analogWrite(BLUE, 255-c->blue);
analogWrite(RED, 255-c->red);
Which "first part"?
The first line is a function declaration. The function return type, name, and arguments are defined. colore is a function that returns nothing and takes a pointer of undefined type.
The next line declares a variable, c that is a pointer of type RGB.
The next line makes that pointer point to the data that was input to the function.
Pretty stupid construct, really. The function should be declared to take a pointer of type RGB, and all that silliness could have been avoided.
It a function definition:
void colore(void *ptr) { // Pass in a typeless pointer
RGB *c; // Define a Red Green Blue type of pointer
c = (RGB *)ptr; // Cast the void pointer memory address to be an RGB pointer, assign to c
analogWrite(GREEN, 255-c->green); // 255 minus (*c).green, which subtracts the green element from 255
analogWrite(BLUE, 255-c->blue);
analogWrite(RED, 255-c->red);
}
I doubt that most programmers would write it this way.
Thank you for the answer, i tought was stupid but still didnt understood, i try to explain better, this the code i'm trying to understand, is not clear to me the use of the table and struct.
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
struct RGB {
byte red;
byte green;
byte blue;
};
struct temps {
float min;
float max;
RGB color;
};
int RED = 11;
int GREEN = 9;
int BLUE = 12;
int temps_table_length = 11;
temps temps_table[] = {
// R G B Color table
{15,17,{0,255,192}},
{17,19,{0,255,128}},
{19,21,{0,255,64}},
{21,23,{64,255,0}},
{23,25,{128,255,0}},
{25,27,{192,255,0}},
{27,29,{255,255,0}},
{29,31,{255,192,0}},
{31,33,{255,128,0}},
{33,35,{255,64,0}},
{35,37,{255,0,0}}
};
void color(void *ptr) {
RGB *c;
c = (RGB *)ptr;
analogWrite(GREEN, 255-c->green);
analogWrite(BLUE, 255-c->blue);
analogWrite(RED, 255-c->red);
}
void color_for_temps(float t) {
for (int i = 0; i < temps_table_length; i++) {
temps ts = temps_table[i];
if (t > ts.min & t <= ts.max) {
color(&ts.color);
return;
}
}
}
void setup(void)
{
Serial.begin(9600);
sensors.begin();
}
void loop(void)
{
//digitalWrite(12, HIGH);
sensors.requestTemperatures(); // Send the command to get temperatures
float temp = sensors.getTempCByIndex(0);
color_for_temps(temp);
Serial.print(temp);
Serial.print(" C");
Serial.print("\t");
//Serial.print((temp-32)/1.8);
//Serial.print(" C");
Serial.print("\r\n");
delay(50);
}
Your code have a bug. In function color_for_temps
, the line:
if (t > ts.min & t <= ts.max) {
should be:
if (t > ts.min && t <= ts.max) {
pepe...
i'm sorry to bother, can you suggest me the correct way to use the pointer instead of the doubble pointers?
(NB: in fact, one could use « ptr » directly instead of using the intermediate variable « c ».)
No, you can't, because ptr is NOT a pointer of type RGB. void pointers do not have appropriate members (or any members, for that matter).
How about:
void colore(const RGB & rgb) {
analogWrite(GREEN, 255 - rgb.green);
analogWrite(BLUE, 255 - rgb.blue);
analogWrite(RED, 255 - rgb.red);
}
Now you don't need pointers.
but since ptr is intended to point to RGB structures only, the best way to write the code is :
The BEST way to write the code is to define ptr as the proper type to begin with. Then, none of this nonsense with casting would be necessary.
pepe,
I think you are over-optimzing. a single 2 byte value on the stack is not going to make or break a sketch. I am a long time assembler programmer, from back in the days where every byte mattered.
However, your code that type-casts the pointer on every line is ugly and hard to read. I'd use a temporary variable of the correct type for readability and ease of typing.
Even on a 6502, which only has a 256 byte stack, using an extra 2 byte local variable is not usually a problem.
Your final solution of changing the type of the variable to a typed RGB pointer is the best (or the other poster's solution of passing &RGB...)
pepe:
PaulS:
(NB: in fact, one could use « ptr » directly instead of using the intermediate variable « c ».)
No, you can't, because ptr is NOT a pointer of type RGB. void pointers do not have appropriate members (or any members, for that matter).
Of course I can ! 8)
Moreover, void pointers always have to be type-casted to a particular non-void pointer type to be used.
Here, the type-casting is done at the line :
c = (RGB *)ptr;
but this approach uselessly consumes the size of a pointer on the stack (... if the compiler's optimizer is not clever enough to fix the developper's clumsiness).
Instead, one could write :
void colore(void *ptr) {
analogWrite(GREEN, 255 - ((RGB*)ptr)->green);
analogWrite(BLUE, 255 - ((RGB*)ptr)->blue);
analogWrite(RED, 255 - ((RGB*)ptr)->red);
}
but since *ptr* is intended to point to *RGB* structures only, the best way to write the code is :
void colore(RGB *ptr) {
analogWrite(GREEN, 255 - ptr->green);
analogWrite(BLUE, 255 - ptr->blue);
analogWrite(RED, 255 - ptr->red);
}
Thank you for that endorsement.
I tried a sample program with both methods (the pointer and the reference) and they generated identical sized code, and indeed, identical machine code.
The diff between the two .elf files:
nick@Ubuntu:~$ diff temp.txt temp2.txt
122c122
< 0000011a <_Z6coloreRK5t_RGB>:
---
> 0000011a <_Z6coloreP5t_RGB>:
178c178
< 18e: 0e 94 8d 00 call 0x11a ; 0x11a <_Z6coloreRK5t_RGB>
---
> 18e: 0e 94 8d 00 call 0x11a ; 0x11a <_Z6coloreP5t_RGB>
The only difference was the name-mangling of the function call (in the comment), the actual code was the same.
So, I recommend using proper references. All this mucking around with void pointers is, IMHO, crap. It makes the code less readable, much more prone to errors, and harder to maintain.
pepe:
But since Arduino's language supports some C++ syntax
Only some?
I'd argue that non-support for certain features is semantic, not syntactic, but it's a fine line.
... But among the concerned features, the template class issue seems to be much more a matter of syntax than a matter of semantic.
Templates are fully supported, are you suggesting they are not? We have the STL (standard template library) running with no problems.
Anyway, the point is that one must keep in mind that Arduino's language is mostly C/C++, but absolutely not exactly C++.
It is in fact exactly C++ with some things disabled on the compiler command-line, like exceptions. It's not like another "almost-C++" compiler someone has written and got some things wrong. It is the g++ compiler, with output routines adapted to write to this particular processor's machine code.
... but many of my C++ programs just did not compile or run properly.
Excluding code with exceptions, can you post an example?
If they didn't run properly, they may have simply required more RAM than was available.
As to why the Arduino disables exceptions, this paragraph may explain it:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html
And what it to be gained, tinkering in the back alleys with a language like this? Exception handling overhead can be measured in the size of the executable binary, and varies with the capabilities of the underlying operating system and specific configuration of the C++ compiler. On recent hardware with GNU system software of the same age, the combined code and data size overhead for enabling exception handling is around 7%. Of course, if code size is of singular concern than using the appropriate optimizer setting with exception handling enabled (ie, -Os -fexceptions) may save up to twice that, and preserve error checking.
Possibly the goal of saving 7% of code size was deemed more important, when space is tight, than enabling exceptions especially in an environment which is aimed at beginners.
I don't know if there is a way of disabling -fno-exceptions on the command line. It could be worth attempting it and seeing how well things compile.
Also see here:
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
It looks like maybe this version does not support exceptions at all.
Thanks to all you guys... became something interesting... i tried the code on an Sparkfun MicroPro, i will test also on an Arduino Mega maybe that can be the explanation of my errors ( i believe Gammon solution should be the best..like always...).
Thanks to Gammon, but the result using his way is :
"
Test1:26: error: expected ',' or '...' before '&' token
Test1:26: error: ISO C++ forbids declaration of 'RGB' with no type
Test1.ino: In function 'void colore_for_temps(float)':
Test1:468: error: invalid conversion from 'RGB*' to 'int'
Test1:468: error: initializing argument 1 of 'void colore(int)'
"
Solution of Pepe :
""
Test1:26: error: variable or field 'colore' declared void
Test1:26: error: 'RGB' was not declared in this scope
Test1:26: error: 'ptr' was not declared in this scope
""
1° Solution of DancanC before suggest Pepe way
" mh.... no error,.. looks working ....
Anyway, thanks to everybody for the "free lesson"...
My way works, but you have to fiddle slightly, due to the annoying way that the IDE pre-processes your source. This is not a language issue, but a preprocessing issue.
First make this file (add a tab in the IDE to do this):
rgbStuff.h
struct RGB {
byte red;
byte green;
byte blue;
};
Then make your main sketch:
#include <Arduino.h>
#include "rgbStuff.h"
int RED = 11;
int GREEN = 9;
int BLUE = 12;
void colore(RGB & rgb) {
analogWrite(GREEN, 255 - rgb.green);
analogWrite(BLUE, 255 - rgb.blue);
analogWrite(RED, 255 - rgb.red);
}
void setup ()
{
RGB foo;
colore (foo);
} // end of setup
void loop () { }
Now that compiles. It is because of the way the IDE mucks around with your source. If you put the RGB declaration in the main sketch the preprocessed file looks like this:
#line 1 "sketch_sep09a.ino"
#include "Arduino.h"
void colore(RGB & rgb); // <----------- function prototype too early in code
void setup ();
void loop ();
#line 1
struct RGB {
byte red;
byte green;
byte blue;
};
int RED = 11;
int GREEN = 9;
int BLUE = 12;
void colore(RGB & rgb) {
analogWrite(GREEN, 255 - rgb.green);
analogWrite(BLUE, 255 - rgb.blue);
analogWrite(RED, 255 - rgb.red);
}
void setup ()
{
RGB foo;
colore (foo);
} // end of setup
void loop () { }
It has generated function prototypes (first few lines) however the prototypes are generated before the RGB structure is defined, and thus they fail.
The work-around is to put your structures, typedefs, etc. into a .h file (which is standard C/C++ practice anyway) and then this problem goes away.
pepe:
[quote author=Nick Gammon link=topic=265364.msg1873741#msg1873741 date=1410208831]
... but many of my C++ programs just did not compile or run properly.
Excluding code with exceptions, can you post an example?
template<class Type> Type mean(Type value1, Type value2)
{
Type result = (value1 + value2)/2;
return result;
}
int i,j;
double a,b;
int test1()
{
i = 100;
j = 200;
return mean(i,j);
}
double test2()
{
a = 10.0;
b = 20.0;
return mean(a,b);
}
...
[/quote]
Exactly the same comments that I made above apply to your example. Move the templated function into a .h file:
mydefs.h
template<class Type> Type mean(Type value1, Type value2)
{
Type result = (value1 + value2)/2;
return result;
}
Now your main code is:
#include <Arduino.h>
#include "mydefs.h"
int i,j;
double a,b;
int test1()
{
i = 100;
j = 200;
return mean(i,j);
}
double test2()
{
a = 10.0;
b = 20.0;
return mean(a,b);
}
void setup () { }
void loop () { }
That compiles fine. This is not a language issue, it is an annoying-IDE issue. Personally I wish they would stop doing that and let people spend 5 minutes learning how to use function prototypes.
pepe:
But on Arduino, dividing by zero is allowed, no exception is thrown nor catched, a (wrong) result is provided anyway, and the calculations go on as if everything is ok...
According to the C++ Standard:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division
of the first expression by the second. If the second operand of / or % is zero the behavior is undefined.
So the compiler is doing exactly what it is supposed to do: undefined behaviour.