Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Чёрт, да этот код от ra9ust в 100 раз круче регулярных выражений в плане write-only-code.

Добавлено after 11 minutes 25 seconds:
Ничего непонятно:
Спойлер

Код: Выделить всё

if((day==32&&month==1)||(day==29&&month==2)||(day==32&&month==3)||(day==31&&month==4)||
 (day==32&&month==5)||(day==31&&month==6)||(day==32&&month==7)||(day==32&&month==8)||
 (day==31&&month==9)||(day==32&&month==10)||(day==31&&month==11)){month++;day=1;}
 if(day==32&&month==12){month=1;day=1;year++;}
Просто переписано с отступами: уже понятно, что хотел автор, при этом хорошо видна ошибка с февралём в високосные годы
Спойлер

Код: Выделить всё

if ((day == 32 && month == 1) || (day == 29 && month == 2) ||
        (day == 32 && month == 3) || (day == 31 && month == 4) ||
        (day == 32 && month == 5) || (day == 31 && month == 6) ||
        (day == 32 && month == 7) || (day == 32 && month == 8) ||
        (day == 31 && month == 9) || (day == 32 && month == 10) ||
        (day == 31 && month == 11))
{
    month++;
    day = 1;
}
if (day == 32 && month == 12)
{
    month = 1;
    day = 1;
    year++;
}
А как бы такую логику делал я:
Спойлер

Код: Выделить всё

// Функция определяет число дней в месяце, уже с учётом високосных годов
static uint8_t DaysInMonth(void)
{
	uint8_t ret = month;
	if (ret == 2) {
		ret = year & 0x03;
		ret = (ret ? 29 : 28);
	} else {
		if (ret > 7)
			ret++;
		ret |= 30;
	}
	return ret;
}
// Дальше логика автора:
if (day > DaysInMonth()) {
    day = 1;
    month++;
}
if (month >= 12) {
    year++
}
Контактная информация:
Реклама
Грызет канифоль
Сообщения: 291
Зарегистрирован: Чт ноя 06, 2014 13:09:06

Сообщение viiv »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3220452#p3220452"]А как бы такую логику делал я:
Спойлер

Код: Выделить всё

// Функция определяет число дней в месяце, уже с учётом високосных годов
static uint8_t DaysInMonth(void)
{
	uint8_t ret = month;
	if (ret == 2) {
		ret = year & 0x03;
		ret = (ret ? 29 : 28);
	} else {
		if (ret > 7)
			ret++;
		ret |= 30;
	}
	return ret;
}
}
[/uquote]

1)

Код: Выделить всё

ret = (ret ? 29 : 28);
29<==>28 помянять бы местами
2) 2100 (2200) году будет неверно работать, но это уже мелочи.
3) чтобы понять, надо напрячься :)) комментарий бы добавить к строке " ret |= 30;"
завести массив кол-ва дней в месяцах (во флеш памяти) и индексироваться - просто, понятно с первого взгляда, и займен не намного больше места
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="viiv",url="/forum/viewtopic.php?p=3220521#p3220521"]завести массив кол-ва дней в месяцах (во флеш памяти) и индексироваться - просто, понятно с первого взгляда, и займен не намного больше места[/uquote]
Если оптимизировать вариант WiseLorda, например, так:

Код: Выделить всё

uint8_t DaysInMonth()
{
	if (month == 2)  return 28 + !(year & 3);
	return month + (month >> 3) | 30;
}
то разница с функцией на основе таблицы получается 24 байта для STM32F4.
А хотя нет, похоже это из-за того, что я функцию в цикле вызывал, без него 12 байт.
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

это уже компактность ради компактности, а не читаемости
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

viiv писал(а): 29<==>28 помянять бы местами
Мда... и ошибка уже старая...

Как говорится, срочно в номер: проект раз, проект два, проект три
Контактная информация:
Реклама
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

[uquote="Reflector",url="/forum/viewtopic.php?p=3220534#p3220534"]Если оптимизировать вариант WiseLorda, например, так:

Код: Выделить всё

uint8_t DaysInMonth()
{
	if (month == 2)  return 28 + !(year & 3);
	return month + (month >> 3) | 30;
}
[/uquote]
Тогда уж можно вообще одной строкой написать :

Код: Выделить всё

return (month == 2) ? (28 + !(year & 3)) : (month + (month >> 3) | 30);
:))
Реклама
Грызет канифоль
Сообщения: 291
Зарегистрирован: Чт ноя 06, 2014 13:09:06

Сообщение viiv »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3220589#p3220589"]Мда... и ошибка уже старая...[/uquote]

Выносить определение високосности в отдельную функцию (по желанию inline) и всегда (во всех проектах) использовать ее
Спойлер

Код: Выделить всё

/*
 * високосный ли год
 *   year (c 2000-го года): 0=2000, 1=2001, ...
 *
 * c 2000 по 2255 годы: 2100 и 2200 не являются високосными
 */
__INLINE__ bool_t is_leap_year (uint8_t year)
{
        if (year & 0x03)
                return 0;

#ifdef LEAP_YEAR_EXEPTIONS  /* съэкономим несколько байт, если не проверяем исключения (годы: 2100 и 2200)*/
        if (year == 100 || year == 200)
                return 0;
#endif

        return 1;
}
Тогда Ваш код еще понятней станет (не очивидные с первого взляда места я бы откомментировал):
Спойлер

Код: Выделить всё

uint8_t DaysInMonth (uint8_t month, uint8_t year)
{
   if (month == 2)
        return is_leap_year (year) ? 29 : 28;

   if (month > 7)            /* длинные и короткие месяцы чередуются, исключение: */
      month++;               /*  после длинного июля идет длинный август  */

   return month |= 30;       /* используется только младший бит month */
}
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

Ну вот, вчерашнее сравнение настроек переменных с еепром ужалось вот до такой функции.
Вложения
454488.txt
(414 байт) 210 скачиваний
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

А зачем фигурные скобки ужимать в кучу ? Смотрится отвратительно.

Добавлено after 3 minutes 48 seconds:
Что уже не так написали :

Код: Выделить всё

void contr_eep (void)
{   
for(comp=0;comp<66;comp++){ if(mass[comp]!=eep_mass[comp])result=0;}  if(result==1){delayt=0;while(delayt<200){lcd_gotoxy(0,0);lcd_putsf("  TEST EEPROM         OK!       ");}w=0;}else{lcd_gotoxy(0,0);lcd_putsf("  TEST EEPROM       FAILURE!    ");if(eeppp&0b0011111110010000){PORTB.5=0;}else{PORTB.5=1;}if(PINC.3==0){PORTB.5=0;dreb_0=6;w=0;}} //пищит каждые примерно 2 минуты
}
?
Всё в одной строке :))
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

Да я уже как-то привык про скобки. Про что уже не так написал , что-то не понял.
Грызет канифоль
Сообщения: 291
Зарегистрирован: Чт ноя 06, 2014 13:09:06

Сообщение viiv »

ra9ust, структурируйте код.

Хотим сохранять конфигурацию в EEPROM. Отлично. Зачем? Чтобы при сбросе/включении начать работать с сохраненной конфигурацией.
1) Пользователю не интересно видеть сообщение "TEST EEPROM OK! " Зачем оно? Если при включении самотестирование проходит - молча начинаем работать. Представьте, включаете Вы телевизор, а там:

Код: Выделить всё

Тestng flash memory...Ok
Testing SRAM...Ok
Testing EEPROM...Ok
Testing power supply voltages...Ok
....
2) У вас есть конфигурация устройства. Так? Не вижу причин не зафиксировать это средствами языка программирования (объявить соотвктствующую структуру):

Код: Выделить всё

typedef struct _device_config_t {
   // здесь все параметры конфигурации
} device_config_t;
3) mass[] - конфигурация в SRAM eep_mass[] - конфигурация в EEPROM. Так?
Непонятно, зачем их сравнивать. mass откуда берется? Читается из EEPROM?
Т.е. Вы прочитали EEPROM, работаете-работаете, а затем обнаруживаете,
что EEPROM (или конфигурация в SRAM) странным образом изменилась.

При старте устройства желательно бы проверить целостность конфигурации в EEPROM (например, питание устройства может быть отключено в момент записи конфигурации), выбирайте:
a) в EEPROM хранить контрольную сумму
б) в EEPROM держать несколько копий
в) комбинация двух методов
г) что-то еще

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

Код: Выделить всё

 void device_default_config (device_config_t* c) {
   // устанавливаем значения по умолчанию
}
б) функцию загрузки конфигурационных параметров:
Спойлер

Код: Выделить всё

/* например, есть функции чтение байта из EEPROM по указанному адресу */
uint8_t eeprom_read_byte (unsigned addr);
/* мы хотим контолировать целестность сохраненной конфигурации посредсвом контрольной суммы */
uint16_t cksum_update (uint16_t cksum, uint8_t);


/* возвращает 0, если в EEPROM лежит плохая конфигурация, и значения конфигурационных
   параметров установлены в начальное состояние */
bool_t device_load_config (device_config_t* c) {
    uint8_t data;
    uint16_t cksum = CKSUM_INIT_VALUE; /* начальное значение контрольной суммы */
    uint16 addr = DEVICE_CONFIG_ADDR; /* начиная с DEVICE_CONFIG_ADDR лежит конфигурация устройства */
    uint8_t *p = (uint8_t *) (c);
    uint8_t *limit = p + sizeof (*c);

    while (p < limit) {
         data = eeprom_read_byte (addr++);
         cksum = cksum_update (cksum, data);
         *p++ = data;
    }
    /* читаем дополнительно байты контрольной суммы */
    cksum = cksum_update (cksum, eeprom_read_byte (addr++));
    cksum = cksum_update (cksum, eeprom_read_byte (addr));
    if (cksum != CKSUM_GOOD) {    /* контрольная сумма плохая */
        device_default_config (c);         /* сбрасываем конфигурацию */
        return 0;
    }
    
    return 1;
};
функция device_load_config () будет нормально работать во ВСЕХ ваших проектах,
достаточно чтобы была определена device_config_t, функции чтения EEPROM, функции контрольной суммы.

в) функцию сохранения конфигурационных параметров.
г) ...
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

Ну так это всё у меня и сделано, естественно так как мне удобно.
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

[uquote="ra9ust",url="/forum/viewtopic.php?p=3220795#p3220795"]Про что уже не так написал , что-то не понял.[/uquote]
как минимум, это должно выглядеть так
Спойлер

Код: Выделить всё

void contr_eep (void){
    for(comp=0;comp<66;comp++){
        if(mass[comp] != eep_mass[comp])
            result=0;
    }
    if(result == 1){
        delayt=0;
        while(delayt < 200){
            lcd_gotoxy(0,0);
            lcd_putsf("  TEST EEPROM         OK!       ");
        }
        w=0;
    } else {
        lcd_gotoxy(0,0);
        lcd_putsf("  TEST EEPROM       FAILURE!    ");
        if(eeppp & 0b0011111110010000){
            PORTB.5=0;
        } else {
            PORTB.5=1;
        }
        if(PINC.3==0){
            PORTB.5=0;
            dreb_0=6;
            w=0;
        }
    }
}
опять магические числа 66 и 0b0011111110010000
что такое mass? Давайте угадаю - "массив". Нет, нет и нет. Переменная должна называться осмысленно.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

АА, ну насчет как выглядит тут вопрос не стоит, это уж как мне удобнее, интересны были мнения насчет самой логики написания, поправил код, появилось еще 2кб дополнительного пространства.
Странно, почему магические то? Ну не пишу я комментарии на очевидные для меня куски кода, просто мне так удобнее, а раз удобно значит привычно. Вот как-то так. Продолжаем обсуждение.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ra9ust писал(а):Ну не пишу я комментарии на очевидные для меня куски кода, просто мне так удобнее, а раз удобно значит привычно. Вот как-то так. Продолжаем обсуждение.
я-то и до этого не принимал участие в обсуждении, а после этого, по моему скромному мнению, и всем остальным должно стать противно обсуждать. раз вам так удобнее - зачем вы вообще спрашиваете чужого мнения? ну и ковыряйтесь в своем коде сами.

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

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

вам удобнее потому, что вы успели привыкнуть к этому говну. Распривыкайте обратно и учитесь делать правильно.
ra9ust писал(а):почему магические то?
потому, что никак не названы. И совершенно неважно, насколько их значение очевидно для того, кто в теме.

ну вот для примера. Все, кто использует modbus, знают коды функций, что там Read Holding registers это 03, Write single Holding register это 06 и далее. Вроде как разберутся в случае чего. Но использовать их прям вот так, как числа - крайне фиговая практика. Потому пишем:
Спойлер

Код: Выделить всё

...
typedef enum {
	MB_FUNC_READ_HOLDING_REGISTERS = (uint8_t) 3,
	MB_FUNC_READ_INPUT_REGISTERS = (uint8_t) 4,
	MB_FUNC_WRITE_SINGLE_REGISTER = (uint8_t) 6,
	MB_FUNC_DIAGNOSTICS = (uint8_t) 8
} mb_function_t;
...
...
    switch (MB_ADU_FUNCTION) {
		case MB_FUNC_DIAGNOSTICS:
		    mb_function_diagnostic();
		    break;
		case MB_FUNC_READ_HOLDING_REGISTERS:
		    mb_function_read_registers();
		    break;
		case MB_FUNC_READ_INPUT_REGISTERS:
		    mb_function_read_registers();
		    break;
		case MB_FUNC_WRITE_SINGLE_REGISTER:
		    mb_function_write_single_register();
		    break;
		default:
		    mb_raise_exception(MB_EXCEPTION_FUNCTION_UNSUPPORTED);
	}
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

Качественного в смысле самого исполнения кода, а не того что пробел не сделал или скобки не там поставил.Понятно всё с вами.
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

чтобы подсказать что-то по поводу "самого исполнения кода", надо сначала прочитать ваш код и понять, что он делает. И тут у нас проблема: вамвитььудобнаписатьигонитаккагпринято,и,раз,для,вас,все;ачивидна,высчетаетештоудобствочитающихниважна. Тут понимаете, какая штука: считаемые вами неважными пробелы, отступы, скобки, названия идентификаторов, структурирование кода вообще имеют такую же роль, как и правила орфографии, пунктуации и семантики естественного языка. Их же вы почему-то не игнорируете, так?
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 378
Зарегистрирован: Сб сен 19, 2009 07:02:19

Сообщение shindax »

[uquote="ra9ust",url="/forum/viewtopic.php?p=3221070#p3221070"]Качественного в смысле самого исполнения кода, а не того что пробел не сделал или скобки не там поставил.Понятно всё с вами.[/uquote]
А что Вам понятно? Все советы, рекомендации, критика, IMHO, были даны по существу. Напустите на самый идеальный код обфускатор, чтобы он заменил все имена переменных, функций, констант, на "отфонарные", а макроподстановок напротив, на прямое включение и что Вы получите? Программа продолжит выполняться точно-так-же, как и с осмысленными именами сущностей, но кто сможет такой код поддерживать, дополнять, изменять? Ваш код обфусцирован изначально. :) "Вопрос 'Как писать хорошие программы' из разряда 'Как писать хорошую английскую прозу'". Ч. Уэзрелл. Вы пока делаете это хреново. Как Вы будете делать это дальше - Ваше личное дело, вот только именно Вы предложили к рассмотрению свой код, а не те, кто вам здесь отвечал. Так-что пробелы, скобки должны быть ( ну или их хотя-бы рекомендуется ставить ) в нужное время, в нужном месте. Не нравятся вам общепринятые правила, так пишите, как Вам хочется, но имейте в виду, однажды с ростом программы ( а с таким подходом почти наверняка ) , у Вас неизбежно появятся трудноуловимые ошибки. Желающих исследовать ваши неряшливые портянки кода, найдётся немного желающих. Так-что умерьте гордыню и научитесь адекватно и вдумчиво воспринимать справедливую критику.
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 375
Зарегистрирован: Чт июн 24, 2010 20:58:59

Сообщение ra9ust »

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

Вернуться в «Разные вопросы по МК»