Эта функция C записана в плохой форме?

Я следую, (перефразируемая) молитва с открытым исходным кодом - фиксируют рано, часто фиксируют.

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

Эта стратегия фиксации часто особенно полезна в непрерывных средах интеграции, поскольку она позволяет интеграционное тестирование против других усилий по разработке, давая раннее обнаружение проблем.

5
задан Steve Melnikoff 4 December 2009 в 16:35
поделиться

11 ответов

деление по модулю и целочисленное деление могут быть очень дорогими. Я не знаю о вашей конкретной архитектуре, но думаю, что и там это дорого.

Если вам нужны оба, деление и по модулю, сделайте одно из них и получите другое умножением / разностью.

q =p/10;
r = p - q*10;
4
ответ дан 18 December 2019 в 07:09
поделиться

Я бы, наверное, написал это как:

char byte_to_ascii(char value_to_convert, volatile char *converted_value)
{
 if (value_to_convert < 10) {
  return value_to_convert + '0';
 } else {
  converted_value[0] = (value_to_convert / 10) + '0';
  converted_value[1] = (value_to_convert % 10) + '0';
  return 0;
 }
}
4
ответ дан 18 December 2019 в 07:09
поделиться

Я бы определенно избегал использования чего-либо с плавающей запятой на PIC. И я бы постарался не использовать никаких делений. Сколько раз вы видите, что на ЖК-дисплей отправляется символ, отличный от ascii? Можете ли вы сохранить его в памяти ЖК-дисплея, а затем вызвать его по положению в памяти?

Вот как в моем коде выглядит деление на 10, обратите внимание на 17 циклов, которые ему нужно выполнить. Подумайте, сколько времени это займет, и убедитесь, что вас больше ничего не ждет.

61:                         q = d2 / 10;
 01520  90482E     mov.b [0x001c+10],0x0000
 01522  FB8000     ze 0x0000,0x0000
 01524  2000A2     mov.w #0xa,0x0004
 01526  090011     repeat #17
 01528  D88002     div.uw 0x0000,0x0004
 0152A  984F00     mov.b 0x0000,[0x001c+8]

Если вы выполняете что-либо в своем коде с плавающей запятой, загляните в память программы после того, как вы ее скомпилировали, на вкладке «Символьные» (чтобы вы могли ее прочитать) и найдите код с плавающей запятой, который должен включены. Вы найдете его вверху (в зависимости от вашего кода), вскоре (иш) после метки _reset.

Мой начинается со строки номер 223 и адреса памяти 001BC с _ floatsisf, продолжается несколькими дополнительными метками (_fpack, _divsf3 и т. Д.) И заканчивается _funpack, последней строкой 535 и адресом памяти 0042C. Если вы можете обработать (42C-1BC = 0x270 =) 624 байта потерянного программного пространства, отлично, но у некоторых чипов есть только 2 КБ пространства, и это не вариант.

Если возможно, вместо чисел с плавающей запятой попробуйте использовать арифметику с фиксированной запятой с основанием 2.

Если вы не можете ссылаться на все массивы байтов на ЖК-дисплее, проверяли ли вы, что вы не пытаетесь отправить нуль (это хороший адрес), но его останавливает проверка кода на конец строки ascii? (со мной такое бывало раньше).

и т. д.) и заканчивается _funpack, последней строкой 535 и адресом памяти 0042C. Если вы можете обработать (42C-1BC = 0x270 =) 624 байта потерянного программного пространства, отлично, но у некоторых чипов есть только 2 КБ пространства, и это не вариант.

Вместо плавающей запятой, если это возможно, попробуйте использовать арифметику с фиксированной запятой в базе 2.

Что касается невозможности ссылаться на все массивы байтов на вашем ЖК-дисплее, вы проверили, чтобы убедиться, что вы не пытаетесь отправить нуль (это хороший адрес), но его останавливает проверка кода на конец строки ascii? (со мной такое бывало раньше).

и т. д.) и заканчивается _funpack, последней строкой 535 и адресом памяти 0042C. Если вы можете обработать (42C-1BC = 0x270 =) 624 байта потерянного программного пространства, отлично, но на некоторых чипах есть только 2 КБ пространства, и это не вариант.

Вместо плавающей запятой, если это возможно, попробуйте использовать арифметику с фиксированной запятой в базе 2.

Что касается невозможности ссылаться на все массивы байтов на вашем ЖК-дисплее, вы проверили, чтобы убедиться, что вы не пытаетесь отправить нуль (это хороший адрес), но его останавливает проверка кода на конец строки ascii? (со мной такое бывало раньше).

попробуйте использовать арифметику с фиксированной запятой в базе 2.

Поскольку невозможно сослаться на все массивы байтов на ЖК-дисплее, проверяли ли вы, не пытаетесь ли вы отправить нуль (который является точный адрес), но его останавливает проверка кода на конец строки ascii? (со мной такое бывало раньше).

попробуйте использовать арифметику с фиксированной запятой в базе 2.

Поскольку невозможно сослаться на все массивы байтов на ЖК-дисплее, проверяли ли вы, не пытаетесь ли вы отправить нуль (который является точный адрес), но его останавливает проверка кода на конец строки ascii? (со мной такое бывало раньше).

7
ответ дан 18 December 2019 в 07:09
поделиться

Is it poor form to convert to floating, call fmod, and convert to integer, instead of just using the % operator? I would say yes. There are more readable ways to slow down a program to meet some timing requirement, for example sleeping in a for loop. No matter what compiler or what tweaking of assembly code or whatever else, this is a highly obfuscated way to control the execution speed of your program, and I call it poor form.

If perfect assembly code means that it works right but it's even slower than the conversions to floating point and back, then use integers and sleep in a for loop.

As for the imperfect assembly code, what's the problem? "at the expense of being able reference the addresses of all my byte arrays"? It looks like type char* is working in your code, so it seems that you can address all your byte arrays the way the C standard says you can. What's the problem?

3
ответ дан 18 December 2019 в 07:09
поделиться

Честно говоря, я бы сказал да ..

Если бы вы хотели b в качестве остатка используйте MOD или самостоятельно:

char a = value_to_convert / 10;
char b = value_to_convert - (10 * a);

Преобразование в / из числа с плавающей запятой никогда не поможет, если только ваши значения действительно не являются числами с плавающей запятой.

Кроме того, Я настоятельно рекомендую придерживаться соглашения о явной ссылке на ваши типы данных как на 'signed' или 'unsigned' и оставлять пустой 'char', если на самом деле является символом (частью строки) . Вы передаете необработанные данные, которые, как мне кажется, должны быть символом без знака (конечно, при условии, что источник имеет значение без знака!). Легко забыть, если что-то должно быть подписано / неподписано, а с голым символом вы получите всевозможные ошибки при наведении курсора.

Большинство 8-битных микросхем требуют бесконечности для умножения (и более чем навсегда для разделение), так что постарайтесь минимизировать их.

Надеюсь, это поможет ..

Вы передаете необработанные данные, которые, как мне кажется, должны быть символом без знака (конечно, при условии, что источник имеет значение без знака!). Легко забыть, если что-то должно быть подписано / неподписано, а с голым символом вы получите всевозможные ошибки пролистывания.

Большинство 8-битных микросхем требуют бесконечности для умножения (и более чем навсегда для разделение), так что постарайтесь минимизировать их.

Надеюсь, это поможет ..

Вы передаете необработанные данные, которые, как мне кажется, должны быть символом без знака (конечно, при условии, что источник имеет значение без знака!). Легко забыть, если что-то должно быть подписано / неподписано, а с голым символом вы получите всевозможные ошибки при наведении курсора.

Большинство 8-битных микросхем требуют бесконечности для умножения (и более чем навсегда для разделение), так что постарайтесь минимизировать их.

Надеюсь, это поможет ..

2
ответ дан 18 December 2019 в 07:09
поделиться

Код, похоже, выполняет две очень разные вещи, в зависимости от того, присвоено ли ему число в диапазоне 0–9 или 10–99. По этой причине я бы сказал, что эта функция написана в плохой форме: я бы разделил вашу функцию на две функции.

1
ответ дан 18 December 2019 в 07:09
поделиться

Поскольку мы обсуждаем деление на 10 здесь ..

Это мой вариант. Это всего лишь простые операции и даже не нужны широкие регистры.

unsigned char divide_by_10 (unsigned char value)
{
  unsigned char q;
  q = (value>>1) + (value>>2);
  q += (q>>4);
  q >>= 3;
  value -= (q<<3)+q+q;
  return q+((value+6)>>4);
}

Ура, Нильс

1
ответ дан 18 December 2019 в 07:09
поделиться

It is typical for optimizers to do unwanted thingies from time to time if you poke around in the internals.

Is your converted_value a global value or otherwise assigned in such a fashion that the compiler knows not to touch it?

0
ответ дан 18 December 2019 в 07:09
поделиться

PIC's don't like doing pointer arithmetic.

As Windows programmer points out, use the mod operator (see below.)

char byte_to_ascii(char value_to_convert, volatile char *converted_value) {

 if (value_to_convert < 10) {
  return (value_to_convert + 48);
 } else {
  char a = value_to_convert / 10;  
  char b = value_TO_convert%10;
  a = a + 48;
  b = b + 48;
  *converted_value = a;
  *(converted_value+1) = b;
  return 0;
 }
}
0
ответ дан 18 December 2019 в 07:09
поделиться

Да, я считаю, что ваша функция:
char byte_to_ascii (char value_to_convert, volatile char * convert_value) {

if (value_to_convert <10) {
return (value_to_convert + 48);
} else {
char a = value_to_convert / 10;
двойной x = fmod ((double) value_to_convert, 10.0);
char b = (char) x;
а = а + 48;
b = b + 48;
* convert_value = a;
* (преобразованное_значение + 1) = b;
возврат 0;

}
}
находится в плохой форме:

Не используйте десятичные числа для символов ASCII, используйте символ, например '@' вместо 0x40.
Нет необходимости использовать функцию fmode .

Вот мой пример:
// Предполагается 8-битный октет
значение символа;
char largeValue;
значение = значение_до_конвертировать / 100;
значение + = '0';
convert_value [0] = значение;
largeValue = value_to_convert - значение * 100;
значение = largeValue / 10; значение + = '0';
convert_value [1] = значение;
largeValue = largeValue - значение * 10; значение + = '0';
convert_value [2] = значение;
преобразованное_значение [3] = '\ 0'; // Нулевой терминатор.

Так как здесь всего 3 цифры, я решил развернуть цикл. Нет ветвей, прерывающих предварительную выборку инструкций. Никаких исключений с плавающей запятой, только целочисленная арифметика.

Если вы начинаете пробелы вместо нулей, вы можете попробовать следующее:
значение = (значение == 0)? '': value + '0';

0
ответ дан 18 December 2019 в 07:09
поделиться

Просто для придурковатости, но несколько операторов return одной и той же функции можно считать плохим тоном (MISRA).

Кроме того, некоторые из приведенных выше обсуждений являются на пределе постоянных оптимизаций. Некоторые задачи следует оставить компилятору. Однако в такой минималистичной встраиваемой среде эти приемы все еще могут работать.

0
ответ дан 18 December 2019 в 07:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: