Работает с gcc, но не с Arduino. ошибка: taking address of temporary array

Мне нужно жестко закодировать 8-байтовые адреса в массивы символов длиной 8. Это должно быть сделано во многих местах моего кода (в области функций), поэтому я попытался придумать однострочный код. Следующее отлично работает в C при компиляции с помощью 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);

    // строка ниже не компилируется с Arduino IDE
    cpaddr(a, (char[]) {0x00, 0x10, 0xFF, 0xCA, 0x00, 0x00, 0xA2, 0x7D});
}

При компиляции на Arduino последняя строка, к которой я стремился, не компилируется. Это дает:

/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

В чем здесь проблема, которая явно не проблема с gcc?

Как это исправить?

, 👍5

Обсуждение

Попытался ли ты void cpaddr(char target[], const char *source), @jantje

Я попробовал ваш точный код с g++ (и gcc) версии 4.8.4 и получил точно такое же сообщение об ошибке, которое вы получили., @Nick Gammon

Я использую 4.9.3. Скриншот результата: http://i.imgur.com/2RJbGwg.png, @Mads Skjern

( type[] ){val, ues} не является допустимым способом создания временного на С++: http://stackoverflow.com/questions/15458883/using-array-init-list-as-temporary-in- c11#comment26614881_18163000 Решение состоит в том, чтобы ввести его., @underscore_d


3 ответа


Лучший ответ:

4

Совершенно верно, использование такого синтаксиса не допускается. Это немного мучительно, но это нормально, так как есть альтернативный метод — своего рода «трюк», если хотите.

Этот трюк заключается в использовании строки, а не массива. В конце концов, строка — это просто массив, просто компилятор обрабатывает ее немного по-другому.

Вместо использования {...} используйте "..." и используйте управляющую последовательность шестнадцатеричных символов \xNN, например :

cpaddr(a, "\x00\x10\xFF\xCA\x00\x00\xA2\x7D");

Вы даже можете потерять свою пользовательскую функцию и использовать стандартную библиотечную функцию - memcpy():

memcpy(a, "\x00\x10\xFF\xCA\x00\x00\xA2\x7D", 8);

На 8-битных AVR вы можете сэкономить оперативную память, используя вариант программы и макрос F():

memcpy_P(a, F("\x00\x10\xFF\xCA\x00\x00\xA2\x7D"), 8);
,

Я думаю, что это должно быть PSTR() вместо F(). F() — это особенный хак Arduino String., @Mikael Patel

F() просто навязывает тип PSTR() для перегрузки. Вы можете использовать любой из них., @Majenko

Из-за типа вы не можете использовать F() напрямую без приведения. Компилятор скажет: «Невозможно преобразовать 'const __FlashStringHelper*' в 'const char*'»., @Mikael Patel

Мой не сделал. Скомпилировалось отлично. Я всегда тестирую перед публикацией кода. Это не приведение, это переинтерпретация_приведения., @Majenko

Но, видимо, не для memcpy_P, поскольку он принимает все, что угодно, т.е. const void*., @Mikael Patel

В любом случае F() является частью "черного списка" класса String. Этого должно быть достаточно, чтобы вместо этого использовать PSTR() :), @Mikael Patel

Это верно ;), @Majenko

Нет, это не так. Определение #define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal))) находится в WString.h, однако между F() и классом String нет никакой связи, за исключением того, что Класс String *использует* его в определенных случаях (как и класс Print). На самом деле, как вы можете видеть из #define, использование PSTR() вместо этого не имеет никакого смысла. F() *уже использует* PSTR(). Его цель - просто создать новый тип, который можно использовать для определения того, находится ли строка в PROGMEM или в RAM. Вот и все., @Nick Gammon

@NickGammon Разве это не в основном для перегрузки, как я упоминал выше? ;), @Majenko

Э-э, да, получается # определить PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) (который по-прежнему является типом const char []) в другой тип, который затем помогает при перегрузке. Так что я согласен, что (после кастинга) они будут одинаковыми. Однако ни PSTR, ни F() не являются «частью класса String, занесенного в черный список». Я не вижу возражений против использования здесь F(). На самом деле ваше предложение сэкономит ОЗУ по сравнению с тем, что я сделал в своем ответе, хотя мое, вероятно, «чище» в том смысле, что вы не добавляете memcpy_P (и убедитесь, что вы правильно указали длину)., @Nick Gammon


1

См. Использование списка инициализации массива как временного в C++11?

Вы можете решить эту проблему, используя const. Это компилируется:

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});
}

Примечание. Мне пришлось изменить ваш массив с char на byte, потому что я получал (действительные) предупреждения о том, что такие вещи, как 0xCA, не помещаются в char.

,

Как сказал Маженко, memcpy будет лучше, чем побайтовое копирование., @Nick Gammon

Я ненавижу, когда люди используют нестандартные типы, специфичные для Arduino, такие как byte, когда есть совершенно хороший и стандартный uint8_t..., @Majenko

Как объяснено в той самой теме, на которую вы ссылаетесь, ( type[] ){val, ues} не является допустимым способом создания временного на С++: http://stackoverflow.com/questions/15458883/using-array-init -list-as-temporary-in-c11#comment26614881_18163000 Решение состоит в том, чтобы ввести его., @underscore_d

В последних версиях IDE используется C++11, поэтому не имеет большого значения, допустимо ли это в C++., @Nick Gammon


0

Как это исправить?

"Char []" не должен компилироваться под c. Это просто недействительно.

Вы можете использовать строку, преобразованную в char * . или просто еще один указатель, как вы уже делали.

,