Работает с 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?
Как это исправить?
@Mads Skjern, 👍5
Обсуждение3 ответа
Лучший ответ:
Совершенно верно, использование такого синтаксиса не допускается. Это немного мучительно, но это нормально, так как есть альтернативный метод — своего рода «трюк», если хотите.
Этот трюк заключается в использовании строки, а не массива. В конце концов, строка — это просто массив, просто компилятор обрабатывает ее немного по-другому.
Вместо использования {...}
используйте "..."
и используйте управляющую последовательность шестнадцатеричных символов \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
См. Использование списка инициализации массива как временного в 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
Как это исправить?
"Char []" не должен компилироваться под c. Это просто недействительно.
Вы можете использовать строку, преобразованную в char * . или просто еще один указатель, как вы уже делали.
- Работает ли конструкция int array[100] = {0} на Arduino?
- Разбор массива объекта в конструкторе библиотеки
- Замена нескольких выводов pinMode() и digitalWrite() на массив
- GCC msg "note: in definition of macro 'max'" сообщение об ошибке
- Массив динамического размера в качестве члена класса
- Почему считается плохой практикой использовать ключевое слово "new" в Arduino?
- Итерация массива объектов
- Как получить размер (sizeof) массива структур
Попытался ли ты 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