Лучший способ уменьшить перегрузку при достаточном литье при переполнении стека

Компилятор avr-gcc предлагает макрос F () как хороший способ определить строки в моих инструкциях и затем поместить строки в программную память. Однако строки в конечном итоге имеют тип __FlashStringHelper, и я получу сообщение об ошибке, если попытаюсь передать их функциям, ожидающим «const char *».

Я могу разыграть каждого из них, и код будет функционировать. Например, этот код будет работать:

int16_t LT_printf(const char *format, ...);
LT_printf((const char *)F("TESTING!\r\n"));

Я также могу определить функцию перегрузки, которая ничего не делает, кроме как получает __FlashStringHelper и затем превращает его в (const char *). Это также работает:

int16_t LT_printf(const __FlashStringHelper *format, ...);
LT_printf(F("TESTING!\r\n"));

Второе решение выполняется менее эффективно, чем первое, но по крайней мере у меня больше нет сотен приведений в моем коде.

Есть ли способ устранить приведения внутри каждого вызова функции, но все же не нужна функция перегрузки?

Отредактировано для добавления дополнительных примеров, которые создают (не то, чтобы я действительно делал какие-либо примеры … Мне просто интересен указатель на const __FlashStringHelper):

typedef struct
{
char test_string[20];
} TEST_STRUCT_TYPE;
const TEST_STRUCT_TYPE PROGMEM test_struct = {"STRUCT TESTING!\r\n"};
const uint8_t PROGMEM test_array[] = {'A', 'R', 'R', 'A', 'Y', ' ', 'T', 'E', 'S', 'T', 'I', 'N', 'G', '!', '\r', '\n', NULL};
const char PROGMEM test_string[] = {"TEST TESTING!\r\n"};

void test()
{
LT_printf(test_string);                       // doesn't need a cast

LT_printf((const char *)F("F TESTING!\r\n")); // these need a cast
LT_printf((const char *)&test_struct);
LT_printf((const char *)test_array);

LT_printf((PGM_P)F("F TESTING!\r\n"));        // this is the cleaner cast
LT_printf((PGM_P)&test_struct);
LT_printf((PGM_P)test_array);
}

Это приводит к такому выводу:

TEST TESTING!
F TESTING!
STRUCT TESTING!
ARRAY TESTING!
F TESTING!
STRUCT TESTING!
ARRAY TESTING!

-1

Решение

  LT_printf(test_string);                       // doesn't need a cast
LT_printf((const char *)F("F TESTING!\r\n")); // these need a cast
LT_printf((const char *)&test_struct);

Вы не можете просто отбросить другой тип данных и ожидать, что он будет работать. Предполагая, что test_string работает, то он ожидает печатать из ОЗУ, а не из PROGMEM, который находится в отдельном адресном пространстве.

Простое решение в вашем случае состоит в том, чтобы получить класс, который LT_printf в (что бы это ни было) из Print а потом print, println и т.д. будет просто работать.

Например, у меня есть библиотека, которая печатает на I2C LCD. Я извлекаю это из Print как это:

class I2C_graphical_LCD_display : public Print

Теперь все, что нужно сделать вашему классу, это реализовать write в вашем классе (т. е. писать один байт) и Print класс заботится обо всем остальном: и запись из RAM, и через PROGMEM через F() макро.

Мой ответ не касается как получить printf работать, хотя вы могли бы посмотреть на этот.

Вам может быть лучше, глядя на Streaming библиотека, которая позволяет вам выводить поток в стиле C ++, а не использовать вывод в стиле printf.


Вот простой способ реализации printf (но только из оперативной памяти), добавив пару вспомогательных функций:

int getChar (FILE *fp)
{
while (!(Serial.available()));
return (Serial.read());
}  // end of getChar

int putChar (char c, FILE *fp)
{
Serial.write (c);
return c;
}  // end of putChar

void setup ()
{
Serial.begin(115200);
fdevopen (putChar, getChar);
}  // end of setup

void loop ()
{
int temp = 30;

printf ("The temperature is %d degrees C.\n", temp);
delay (100);
}  // end of loop

fdevopen говорит стандартной библиотеке ввода-вывода, как получать и размещать символы. В этом конкретном случае я использую Serial, но это может быть Serial1 или SoftwareSerial и др.


Если вы хотите использовать константы PROGMEM (т.е. F()) тогда я думаю, что проще всего использовать потоковую библиотеку. например.

#include <Streaming.h>

void setup ()
{
Serial.begin (115200);
}  // end of setup

void loop ()
{
int temp = 30;
Serial << F("The temperature is ") << temp << F(" degrees C") << endl;
delay (100);
}  // end of loop

Это еще более компактно и экономит оперативную память, используя F() макро. Это тоже довольно читабельно.

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector