5

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?

4

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 Mar 2 '16 at 22:07
  • F() just imposes a type to PSTR() for overloading. You can use either. – Majenko Mar 2 '16 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 Mar 2 '16 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 Mar 2 '16 at 22:31
  • But apparently not on memcpy_P as it takes whatever, i.e. const void*. – Mikael Patel Mar 2 '16 at 22:32
1

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. – Nick Gammon Mar 2 '16 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 Mar 3 '16 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 Jun 26 '16 at 7:12
  • Recent versions of the IDE use C++11, so whether or not it is valid in C++ doesn't really matter. – Nick Gammon Jun 26 '16 at 9:25
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.