Почему Serial.print(1) требует на 228 байт больше программной памяти по сравнению с Serial.print((char)(48+1))?

Только что обнаружил это. Когда я привожу int к char внутри оператора Serial.print, это требует меньше памяти для программы. Я не уверен, почему. Может ли кто-нибудь объяснить это мне? В следующем примере разница составляет 228 байт!

Serial.print(1); // 1676 байт памяти для хранения программ. 184 байта динамической памяти.
Serial.print((char) (48 + 1)); // 1448 байт памяти для хранения программ. 184 байта динамической памяти.

EDIT: Добавление из разных комментариев:

Serial.print('1'); // Sketch использует 1448 байт программной памяти, 184 байт динамической памяти
Serial.write(48 + 1); // Sketch использует 1448 байт программной памяти, 184 байт динамической памяти

EDIT: для int > 9, добавление кавычек в следующем примере экономит 218 байт памяти программы, но добавляет 4 байта к использованию динамической памяти.

Serial.print(123); // 1676/184 байта
Serial.print("123"); // 1458/188 байт
Serial.print(String(123)); // 2772/194 байта

EDIT2: максимальное количество цифр в Arduino-uno int равно 5(?). Вы экономите 80 байт, преобразовывая его в массив символов, по сравнению с простой печатью целого числа:

Serial.print(12345); // 1676/184 байта
char digits[5];
int number = 12345;
for (int i = 4; i >= 0; i--) {
  digits[i] = (number %10) + 48;
  number /= 10; 
}
Serial.print(digits); // 1596/184 байта

Проверить самостоятельно, раскомментировав одно или другое:

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600);
  Serial.print(1); // использует 1676/184 байта
  //. Serial.print((char) (48 + 1)); // использует 1448/184 байта
  // Serial.print('1'); // использует 1448/184 байта
  // Serial.write(48 + 1); // 1448/184 байта
  // Serial.print(123); // 1676/184 байта
  // Serial.print("123"); // 1458/188 байт
  // Serial.print(String(123)); // 2772/194 байта
  // Serial.print(12345); // 1676/184 байта | 1676/184
  // Serial.print("12345"); // 1458/188 байт | 1460/190
  // символьный бафф[5];
  // itoa(12345, buff, 10);
  // Serial.print(buff); // 1604/184 байта
  char digits[5];
  int number = 12345;
  for (int i = 4; i >= 0; i--) {
    digits[i] = (number %10) + 48;
    number /= 10;
  }
  Serial.print(digits); // 1596/184 байта
}
void loop() {
  // поместите сюда ваш основной код для многократного запуска:

}

EDIT: Второй вопрос: не следует ли это как-то оптимизировать? Или я должен всегда сам об этом заботиться? И почему/как? ;)

*символы 0–9 имеют десятичное значение 48–57 в таблице Ascii, поэтому (char)(48 + 0–9) печатает 0–9

, 👍1

Обсуждение

короткий ответ: это не та же функция печати. вы также можете попробовать .print('1') и .print((char) 1), @Juraj

@Juraj Вы правы, я тестировал всегда печатать целое число в сочетании с приведенными выше примерами. И использование памяти в какой-то момент выравнивается. Я предполагаю, что компилятор оптимизирует функцию печати int, если вы печатаете только символы/строки. Наоборот. Что было бы, когда они вызывают разные функции., @Gaai


1 ответ


3

Разница вот в чем:

  • Напечатать этот символ

и

  • Интерпретируйте это целое число как последовательность цифр, вычислите символы ASCII, представляющие каждую цифру по очереди, и распечатайте их.

Как видите, даже простое написание того, что делает второй, занимает больше слов. Печать целого числа требует гораздо больше работы, чем просто печать одного символа. Подумайте о том, что нужно, чтобы напечатать значение 2034578, и как бы вы это сделали, учитывая, что вы можете выводить только отдельные числа 0-9, а данные хранятся не как числа 0-9, а как последовательность только 0 и 1. .

Это требует работы. Много работы.

,

Так почему бы тогда не перевести его на символ в фоновом режиме. Так как это требует меньше работы, много меньше работы;), @Gaai

@Gaai, потому что это не то, что делает перегрузка int .print() в общем случае. Вы не можете правильно напечатать .print(123); с помощью одного приведения и сложения. Вы используете механизм, который позволяет правильно напечатать «123», даже если вы запрашиваете только «1», и поэтому вы платите за это. Ответ правильный., @timemage

print — это удобная функция для простой печати различных типов в виде текста ASCII. Если все, что вам нужно, это напечатать один символ, то вам следует использовать не печать, а запись. Вы сами должны выбрать правильный инструмент для своей работы, @chrisl

@chrisl Ах да. Это имеет смысл. Это следует добавить к ответу! Serial.write(1) стоит столько же, сколько печать одного символа., @Gaai

@Majenko, возможно, вы можете включить в свои ответы параметр Serial.write для отдельных символов / цифр? Тогда никакой разницы в памяти., @Gaai

@Gaai Первый пункт списка «напечатать этот символ» — это единственный символ, на который вы не согласны., @Majenko

@Gaai Относительно Serial.write(1) <- .write() избавит вас от «опасности» случайного вызова перегрузки print(), которая печатает многозначные числа и, возможно, лучше выражает намерение , но это все, что он делает. Он не отправляет 1 как цифру. Таким образом, .write(1) в вашем комментарии выше отправляет управляющий символ, а не цифру. Другими словами, вам по-прежнему нужен + 48, вам просто не нужно приведение (char) к .write() так, как вы делали print()., @timemage

Ну, мой вопрос касался одной цифры int. Это один символ, а также целое число. Но по-прежнему print обрабатывает его как любой int. Используя больше памяти, чем могло бы быть, рассматривая его как char., @Gaai

@timemage конечно ты прав!, @Gaai

Я только что добавил использование памяти Serial.print(123) и Serial.print("123") для полноты картины., @Gaai

Написание моего собственного преобразования по-прежнему экономит 80 байт. Вероятно, вы получите еще больше, если сделаете это умнее. Странно, если вы спросите меня., @Gaai