I need to hard code 8 byte addresses into char arrays of length 8. This must be done many places in my code (in function scope), so I have tried to come up with a one-liner. The following works perfectly in C when compiling with gcc.
char a[8];
void cpaddr(char target[], char *source) {
int i;
for (i=0; i<8; i++)
target[i] = source[i];
}
int main() {
char b[] = {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D};
cpaddr(a, b);
// line below does not compile with Arduino IDE
cpaddr(a, (char[]) {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D});
}
When compiling on Arduino the last line, which is the one-liner I was aiming for, does not compile. It gives:
/home/bob/Desktop/ate/Ate.ino: In function 'int main()':
Ate:101: error: taking address of temporary array
cpaddr(a, (char[]) {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D});
^
exit status 1
taking address of temporary array
What is the problem here, that apparently is not a problem with gcc?
How do I fix it?
3 Answers 3
It is quite right, using that kind of syntax is not allowed. It's a bit of a pain, but it's ok since there is an alternative method - kind of a "trick" if you will.
That trick is to use a string, not an array. After all, a string is just an array, it's just handled slightly differently by the compiler.
Instead of using {...}
use "..."
and use the hexadecimal character escape sequence \xNN
, such as:
cpaddr(a, "\x00\x10\xFF\xCA\x00\x00\xA2\x7D");
You could even lose your custom function and use a standard library function - memcpy()
:
memcpy(a, "\x00\x10\xFF\xCA\x00\x00\xA2\x7D", 8);
On the 8-bit AVRs you can save RAM by using the progmem variant and the F()
macro:
memcpy_P(a, F("\x00\x10\xFF\xCA\x00\x00\xA2\x7D"), 8);
-
I think that it should be PSTR() instead of F(). F() is a very special Arduino String hack.Mikael Patel– Mikael Patel2016年03月02日 22:07:48 +00:00Commented Mar 2, 2016 at 22:07
-
F() just imposes a type to PSTR() for overloading. You can use either.Majenko– Majenko2016年03月02日 22:17:47 +00:00Commented Mar 2, 2016 at 22:17
-
Because of the type you cannot use F() directly without a cast. The compiler will say "cannot convert 'const __FlashStringHelper*' to 'const char*'".Mikael Patel– Mikael Patel2016年03月02日 22:30:00 +00:00Commented Mar 2, 2016 at 22:30
-
Mine didn't. It compiled perfectly fine. I always test before posting code. It's not a cast, it's a reinterpret_cast.Majenko– Majenko2016年03月02日 22:31:11 +00:00Commented Mar 2, 2016 at 22:31
-
But apparently not on memcpy_P as it takes whatever, i.e. const void*.Mikael Patel– Mikael Patel2016年03月02日 22:32:01 +00:00Commented Mar 2, 2016 at 22:32
See Using array init list as temporary in C++11?
You can solve it by using const
. This compiles:
char a[8];
void cpaddr(char target[], const byte *source) {
int i;
for (i=0; i<8; i++)
target[i] = source[i];
}
int main() {
byte b[] = {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D};
cpaddr(a, b);
cpaddr(a, (const byte[]) {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D});
}
Note I had to change your array from char
to byte
because I was getting (valid) warnings that things like 0xCA don't fit into a char.
-
As Majenko said,
memcpy
would be better than doing a byte-by-byte copy.2016年03月02日 20:41:30 +00:00Commented Mar 2, 2016 at 20:41 -
I hate it when people use non-standard arduino specific types like byte, when there is a perfectly good and standard uint8_t available...Majenko– Majenko2016年03月03日 20:14:09 +00:00Commented Mar 3, 2016 at 20:14
-
As explained in the very thread you linked,
( type[] ){val, ues}
is not a valid way to create a temporary in C++: stackoverflow.com/questions/15458883/… The solution is to typedef it.underscore_d– underscore_d2016年06月26日 07:12:18 +00:00Commented Jun 26, 2016 at 7:12 -
Recent versions of the IDE use C++11, so whether or not it is valid in C++ doesn't really matter.2016年06月26日 09:25:41 +00:00Commented Jun 26, 2016 at 9:25
How do I fix it?
"Char []" shouldn't compile under c. It is just invalid.
You can use string, cast to char * . or just another pointer as you did already.
( type[] ){val, ues}
is not a valid way to create a temporary in C++: stackoverflow.com/questions/15458883/… The solution is to typedef it.