Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Множественный выбор, оператор switch
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Aneg
Программирую на С для микроконтроллеров AVR.
Насколько большим может быть этот множественный выбор у оператора switch? Сделал пробный вариант программы на 20 вариантов выбора - работает, а вот на 256 - нет не работает. А нужно сделать выбор для 1024 вариантов. А как поступить в этом случае?
sergeeff
Упаси вас и сохрани от таких программ! Подумайте, зачем вам это надо. Почти всегда можно придумать что-то взамен.
_dem
Switch реализуется через near jump, то есть ограничен +- 127 байт (поправьте, если забыл sm.gif ).

А чем таблица функций не угодила ?
_Pasha
Цитата(Aneg @ Dec 22 2010, 00:26) *
а вот на 256 - нет не работает. А нужно сделать выбор для 1024 вариантов.

Вы забыли рассказать, что за компилер и что за целевой камень, и что значит "не работает"
Цитата(sergeeff @ Dec 22 2010, 00:57) *
Упаси вас и сохрани от таких программ! Подумайте, зачем вам это надо. Почти всегда можно придумать что-то взамен.

Protothreads не в счет? biggrin.gif
sergeeff
Ну и где там switch на 256 case?
Aneg
Компилятор: ICCV7 for AVR (http://www.imagecraft.com/), целевой камень ATmega16.
С помощью АЦП оцифровываю напряжение, пока ограничился на 256 уровнях (8 бит). Далее это значение передается по COM порту в виде 3-х байт ASCII кода. Выбор на switch применяю для перехода от 1-байтового значения к 3-м байт ASCII кода.
sergeeff
С ума сойти можно.

Код
char buf[4];

char inp;             // значение из АЦП
itoa(inp, buf, 10); // библиотечная функция, см. http://ru.wikipedia.org/wiki/Itoa_%28%D0%A1%D0%B8%29
send_to_port(buf, strlen(buf));


Все!!! Никаких switch/case.

или если надо точно 3 байта ASCII

Код
int n = sprintf(buf, "%03d", inp);
send_to_port(buf, n);
Сергей Борщ
QUOTE (sergeeff @ Dec 21 2010, 23:44) *
или если надо точно 3 байта ASCII
А у него через switch() быстрее было! wink.gif
_Pasha
Цитата(sergeeff @ Dec 22 2010, 00:27) *
Ну и где там switch на 256 case?

bb-offtopic.gif это уж зависит от сложности реализуемого алгоритма. Можно и на 1024 и больше sm.gif если психануть.
alexeyv
Если в switch больше 10...20 вариантов (в зависимости от обрабатываемых значений), то я преобразую выбор через таблицу (даже вызов функций). Табличный метод выбора из большого числа значений гораздо выгоднее и по количеству используемой памяти, и по скорости выбора вырианта (всегда одинаковое фиксированное время выбора варианта)
_dem
Продолжим фантазировать sm.gif
Цикл опущен специально .

unsigned char ADCValue = ADC_Read(xxx);

USART_Send( ADCValue / 100 );

ADCValue = ADCValue % 100;
USART_Send( ADCValue / 10 );

ADCValue = ADCValue % 10;
USART_Send( ADCValue );
MrYuran
Код
const char ascii_value_table[3][256] = {
"000","001", ... "256"
}

Как-то так...
Если не так, поправьте, пожалуйста, некогда думать, да и лень
_Pasha
Цитата(_dem @ Dec 22 2010, 10:13) *
Продолжим фантазировать sm.gif

Скачайте хоть какую-нить мудрую книжку себе типа такого прежде чем смешить новизной подхода.
sergeeff
Цитата(Сергей Борщ @ Dec 22 2010, 02:25) *
А у него через switch() быстрее было! wink.gif


Я привел пару примеров только для того, чтобы человек не зацикливался на switch/case. Ясно, что его задачу можно решить еще десятком разных вариантов с разным соотношением скорость/объем кода.
_Pasha
Цитата(MrYuran @ Dec 22 2010, 10:46) *
Как-то так...
Если не так, поправьте, пожалуйста, некогда думать, да и лень

... и еще и быстрее будет, чем switch() lol.gif
Сергей Борщ
QUOTE (MrYuran @ Dec 22 2010, 08:46) *
CODE
const char ascii_value_table[3][256] = {
"000","001", ... "256"
}

Как-то так...
const char ascii_value_table[4][256]. И действительно быстрее. И компактнее. Аплодисменты!
_dem
Цитата(_Pasha @ Dec 22 2010, 09:50) *
Скачайте хоть какую-нить мудрую книжку себе типа такого прежде чем смешить новизной подхода.


Почитайте какую-нибудь мудрую инструкцию типа этой , прежде чем открывать эти ваши Интернеты sm.gif
sergeeff
Автору эти три байта через com-порт наружу передавать и зачем там супер скорость преобразования char->ascii? А 1К под таблицу это не накладно ли будет?
_Pasha
Цитата(_dem @ Dec 22 2010, 10:11) *

Ну вот, Вы - хамить, а я Вам -про преобразование в десятичный код методом сдвига... не помню страницу. Досвидоз!
ReAl
И компактнее :-D — строки всё равно место занимают, а кода меньше даже при табличной реализации switch :-)

_dem
По поводу операций / % — «если уж так по́шло», то тогда через div_t div(value, 100), практически в два раза быстрее.
В смысле стандартную библиотеку языка хотя бы глянуь стоит.

Цитата(Сергей Борщ @ Dec 22 2010, 09:08) *
const char ascii_value_table[4][256]. И действительно быстрее. И компактнее. Аплодисменты!
можно и [3] — если выводить посимвольно или с форматом "%3.3s", оно тогда до отсутствующего терминатора и не дойдёт.
Можно даже "%4.3s", пробельчик перед числом добавить.
MrYuran
Цитата(sergeeff @ Dec 22 2010, 10:14) *
Автору эти три байта через com-порт наружу передавать и зачем там супер скорость преобразования char->ascii? А 1К под таблицу это не накладно ли будет?

Ну это уж автору виднее - что ему дороже, объём или скорость.
Если у меня свободно 30к флеши из 60 и 1к ОЗУ из 2-х, то я не парясь встраиваю функции, размещаю таблицы и щедро развешиваю в памяти хендлы на периферию и виртуальные таймеры с оверхедом в 3-4 раза.
1к в флеши - совершенный пустяк, на мой взгляд. В ОЗУ - да, может быть серьёзно (для AVR), а может быть тоже ерунда (для ARM с 512к ОЗУ)
Сергей Борщ
QUOTE (ReAl @ Dec 22 2010, 09:41) *
можно и [3] — если выводить посимвольно или с форматом

CODE
char const TTT[][3] =
{
        "123",
        "123"
};
QUOTE
error: initializer-string for array of chars is too long
И все попутали порядок задания размерностей.
sergeeff
Цитата(MrYuran @ Dec 22 2010, 11:47) *
Ну это уж автору виднее - что ему дороже, объём или скорость.


Автор как-то ушел в тень. Видимо от избытка чувств.
SasaVitebsk
Цитата(sergeeff @ Dec 22 2010, 11:03) *
Автор как-то ушел в тень. Видимо от избытка чувств.

Он узнал, что кроме switch в языке Си, как не странно, существуют и другие операторы. lol.gif
MrYuran
Цитата(Сергей Борщ @ Dec 22 2010, 10:54) *
И все попутали порядок задания размерностей.

Ну я ж писал - думать лень sm.gif
_dem
ReAL
По поводу операций / % — «если уж так по́шло», то тогда через div_t div(value, 100), практически в два раза быстрее.
В смысле стандартную библиотеку языка хотя бы глянуь стоит.
[/quote]
Угу, а можно еще цикл поставить.
А еще вместо процедуры отправки поставить макрос, что в данном случае на AVR сэкономит, если склероз не подводит, 1 такт по скорости.
А еще сделать таблицу в флеше с инструкциями на каждый случай (т.е. не таблицу адресов функций, а таблицу с кодами ) Это будет ну вообще быстро.
demiurg_spb
Таких перлов я ещё не встречал!
Запас бодрости на весь оставшийся день! Похлеще чем salmari.gif будет:-)
Браво!
singlskv
для байта на авр можно так:
Код
void itoa_byte(unsigned char n, unsigned char *s)
{
  unsigned char ch = 0;

  if ((n >= 100) && (++ch))
  {
    n -= 100;
    if ((n >= 100) && (++ch)) n -= 100;
  }

  *s++ = ch + 0x30;

  ch = (n * 157U + (n << 8)) >> 12;
  *s++ = ch + 0x30;

  ch <<= 1;
  n -= ch;
  ch <<= 2;
  n -=ch;
  *s++ = n + 0x30;
}
достаточно быстро и компактно

а лучше так:
Код
void itoa_byte(unsigned char n, unsigned char *s)
{
  unsigned char ch = 0x30;

  if ((n >= 100) && (++ch) && ((n -= 100) >= 100) && (++ch)) n -= 100;
  *s++ = ch;

  ch = (n * 157U + (n << 8)) >> 12;
  *s++ = ch + 0x30;

  ch <<= 1;
  n -= ch;
  ch <<= 2;
  n -=ch;
  *s++ = n + 0x30;
}


не, лучше всего так:
Код
void itoa_byte(unsigned char n, unsigned char *s)
{
  unsigned char ch = 0x30;

  if ((n >= 100) && (++ch) && ((n -= 100) >= 100) && (++ch)) n -= 100;
  *s++ = ch;

  ch = n * 157U >> 8;
  ch += n;
  ch >>= 4;
  *s++ = ch + 0x30;

  ch <<= 1;
  n -= ch;
  ch <<= 2;
  n -=ch;
  *s++ = n + 0x30;
}

777777
Цитата(Aneg @ Dec 22 2010, 00:31) *
С помощью АЦП оцифровываю напряжение, пока ограничился на 256 уровнях (8 бит). Далее это значение передается по COM порту в виде 3-х байт ASCII кода. Выбор на switch применяю для перехода от 1-байтового значения к 3-м байт ASCII кода.

А если понадобится 16-разрядный АЦП?
sergeeff
Цитата(777777 @ Dec 22 2010, 21:48) *
А если понадобится 16-разрядный АЦП?


Вы ветку прочитали бы.
777777
Цитата(sergeeff @ Dec 22 2010, 22:05) *
Вы ветку прочитали бы.

Что, там кто-то уже высказал такую шутку?
ViKo
А еще... а еще можно передать байт, как есть. А преобразовывать в цифры уже на том конце. sm.gif
Любопытно, если массив объявлен const char DDD[256][3], а заносятся строки "000" и т.д., что будет отброшено - нуль, заканчивающий строку, или старшая цифра?
demiurg_spb
Цитата(ViKo @ Dec 24 2010, 13:03) *
Любопытно, если массив объявлен const char DDD[256][3], а заносятся строки "000" и т.д., что будет отброшено - нуль, заканчивающий строку, или старшая цифра?

нуль, заканчивающий строку, естественно.
Сергей Борщ
QUOTE (demiurg_spb @ Dec 24 2010, 13:34) *
нуль, заканчивающий строку, естественно.
А у меня компилятор ругается (см. сообщение 22).
ViKo
Цитата(Сергей Борщ @ Dec 27 2010, 10:44) *
А у меня компилятор ругается (см. сообщение 22).

А Keil для STM32 скушал без вопросов
Код
const char DDD[2][3] = {"123", "456"};
for (uint32_t i=6; i!=0; i--) USART3->DR = DDD[i/3][i%3];
demiurg_spb
Цитата(Сергей Борщ @ Dec 27 2010, 11:44) *
А у меня компилятор ругается (см. сообщение 22).
Ничего не могу добавить к уже сказанному:-)
singlskv
Цитата(Сергей Борщ @ Dec 22 2010, 10:54) *
Код
char const TTT[][3] =
{
        "123",
        "123"
};

error: initializer-string for array of chars is too long
А Вы ему тогда так скажите:
Код
char const TTT[][3] =
{
        {'1','2','3'},
        {'1','2','3'}
};

Он просто обязан такое сжевать.
Сергей Борщ
QUOTE (singlskv @ Dec 27 2010, 16:08) *
Он просто обязан такое сжевать.
Да как сказать понятно. Видимо это еще одно отличие C и C++. Я проверял на плюсах.
singlskv
Цитата(Сергей Борщ @ Dec 28 2010, 01:11) *
Да как сказать понятно. Видимо это еще одно отличие C и C++. Я проверял на плюсах.
Здесь скорее не отличие С и С++ как стандартов а просто сложившаяся практика применения.
По K&R запись "xyz" эквивалентна {'x','y','z','\0'} то есть массиву из 4 символов,
при этом при инициализации char arr[3]="xyz" компилятор (по K&R) обязан выдавать как минимум предупреждение
о том что количество инициализаторов > размера данных, но видимо программисты никак не хотели сдаваться
и упорно писали такую инициализацию в огромном количестве кода, ну хотя бы просто для экономии памяти...
Вот в итоге и получилось что, де-факто, C компиляторы такое жуют легко, а в С++ просто решили
эту вакханалию прикрыть т.к. он более продвинутый язык по контролю над программистом... sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.