Вопросы по С/С++ (СИ)
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
Куда предлагаете скобки поставить?
Re: Вопросы по С/С++ (СИ)
[uquote="Jack_A",url="/forum/viewtopic.php?p=4542835#p4542835"]Я считаю, что "лишние" скобки не нарушат работу компилятора и не будут в самом деле лишними, даже если программер назубок помнит все приоритеты операций. В конце концов, читаемость исходника будет лучшей. Даже если не заботиться о переносимости.[/uquote]Бессмысленное утверждение. Примерно как утверждать, что брюнетки лучше блондинок. Это дело вкуса. Если для вас толпа скобок в строке улучшает читаемость, то для другого - ухудшает.
Добавлено after 6 minutes 17 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=4542800#p4542800"]ну да, ну да... один и тот же код с -lto в одной версии компилятора собирается нормально и работает, а после сборки в более новой версии компилятора получается 0 байт исполняемого кода... виноват, конечно программист, но не тот, что код писал, а тот, что писал компилятор[/uquote]Приведите пример такого кода. Иначе - это пустой трёп.
PS: Кто-то видит летающие тарелки с зелёными человечками. Но не может привести доказательств.
Кто-то - корректный код, который не компилится правильно компилятором. Но не может его показать.
Это примерно из одной оперы....
Добавлено after 6 minutes 17 seconds:
[uquote="ARV",url="/forum/viewtopic.php?p=4542800#p4542800"]ну да, ну да... один и тот же код с -lto в одной версии компилятора собирается нормально и работает, а после сборки в более новой версии компилятора получается 0 байт исполняемого кода... виноват, конечно программист, но не тот, что код писал, а тот, что писал компилятор[/uquote]Приведите пример такого кода. Иначе - это пустой трёп.
PS: Кто-то видит летающие тарелки с зелёными человечками. Но не может привести доказательств.
Кто-то - корректный код, который не компилится правильно компилятором. Но не может его показать.
Это примерно из одной оперы....
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Пример кода? У меня проект из пары десятков файлов, и публиковать их я не имею желания. LTO от версии к версии avr-gcc дает абсолютно разные результаты: может обнулять выхлоп, может давать полностью рабочий файл минимального размера, а может выдать полностью нерабочий вариант.
Можете не верить (см. ранее о вере), мне пофиг.
Можете не верить (см. ранее о вере), мне пофиг.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
[uquote="jcxz",url="/forum/viewtopic.php?p=4542097#p4542097"][uquote="Martian",url="/forum/viewtopic.php?p=4542069#p4542069"]Если требуется определённый порядок выполнения операций с равным приоритетом, то используют скобки. Знаете такие символы ()? Дичь - это писать без них. А оптимизатор легко упростит, если захочет, потому что ему абсолютно похер, что это программист решил какую-то цифру в числе выделить.[/uquote]Опять бред несёте... Вам бы учебник по си почитать что-ли? Который сами же рекомендовали выше.
Язык си чётко регламентирует как приоритеты операций, так и направление их выполнения на разных уровнях приоритета.
В выражении display % 1000 /100 все операции имеют одинаковый приоритет и направление выполнения - слева направо. И никаких оптимизаций вменяемый оптимизатор здесь не сделает.
А скобки где ни попадя, городят только неумехи, не сумевшие прочитать и усвоить порядок приоритета и направление операций.[/uquote]
Вообще-то, в данном выражении имеются константы. Свёртка констант в выражениях является наиболее простым видом оптимизации. Поэтому данное выражение компилятор вероятно сведёт к выражению display % 10. Или нет?
Язык си чётко регламентирует как приоритеты операций, так и направление их выполнения на разных уровнях приоритета.
В выражении display % 1000 /100 все операции имеют одинаковый приоритет и направление выполнения - слева направо. И никаких оптимизаций вменяемый оптимизатор здесь не сделает.
А скобки где ни попадя, городят только неумехи, не сумевшие прочитать и усвоить порядок приоритета и направление операций.[/uquote]
Вообще-то, в данном выражении имеются константы. Свёртка констант в выражениях является наиболее простым видом оптимизации. Поэтому данное выражение компилятор вероятно сведёт к выражению display % 10. Или нет?
Re: Вопросы по С/С++ (СИ)
[uquote="jcxz",url="/forum/viewtopic.php?p=4543105#p4543105"].Если для вас толпа скобок в строке улучшает читаемость, то для другого - ухудшает.[/uquote]
Типичный пример демагогии: утверждение оппонента преувеличить до бесконечности, доведя до абсурда. Я не практиковал "толпу скобок", равно как и выражение на пол-страницы. Разбивал сложное выражение на части, использовал вспомогательные переменные, благо дефицита оперативной памяти не наблюдается. Трудно представить программу, где все вычисленные части выражения используются только однократно, практически в разных местах кода можем использовать уже вычисленные фрагменты. И скобки нисколько не мешали.

Типичный пример демагогии: утверждение оппонента преувеличить до бесконечности, доведя до абсурда. Я не практиковал "толпу скобок", равно как и выражение на пол-страницы. Разбивал сложное выражение на части, использовал вспомогательные переменные, благо дефицита оперативной памяти не наблюдается. Трудно представить программу, где все вычисленные части выражения используются только однократно, практически в разных местах кода можем использовать уже вычисленные фрагменты. И скобки нисколько не мешали.
Бессмысленное утверждение
Чувствуется рука мастера. Э.Дейкстра, это Вы??это пустой трёп.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
[uquote="Bill_",url="/forum/viewtopic.php?p=4543375#p4543375"]Или нет?[/uquote]А вы как думаете? Свернёт или нет?
Re: Вопросы по С/С++ (СИ)
[uquote="VladislavS",url="/forum/viewtopic.php?p=4543404#p4543404"][uquote="Bill_",url="/forum/viewtopic.php?p=4543375#p4543375"]Или нет?[/uquote]А вы как думаете? Свернёт или нет?[/uquote]
Если написать так: display % (1000/100), то сворачивает. Если скобки убрать, то - нет. Компилятор - IAR STM8.
Если написать так: display % (1000/100), то сворачивает. Если скобки убрать, то - нет. Компилятор - IAR STM8.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
А как правильно? Сворачивать или нет?
Добавлено after 1 minute 26 seconds:
И полагаете ли вы что со скобками это то же самое выражение?
Добавлено after 1 minute 26 seconds:
И полагаете ли вы что со скобками это то же самое выражение?
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Конечно же нет
Правильный результат для display % 1000 /100
Если внезапно (с чего бы вдруг) это сворачивать до display % 10, получим просто 5.
Другое дело, что хороший компилятор может это упростить до display / 100 % 10
Результат будет всегда верным, но числа немного меньшие - вычисления могут быть теоретически быстрее.
P.S. Но вообще, ранее приведённый код - плохой, так как в нём вычисления для каждого разряда разные:
Лучше выводить числа справа налево, тогда там для любого разряда нужно делать лишь %10 и /10, то есть, что-то вроде:
Такой подход и в цикл легко превратить, и работает с любым количеством разрядов...
P.P.S.
Вот пример такого подхода уменя - как-то делал по-быстрому по просьбе человека, который где-то разобыл табло для электронных очередей (с большими семисегментниками) и хотел сделать из этого часы.
Там ещё в этой функции и нули лишние не рисуются, если число маленькое получилось, и знак минуса поддерживается.
Правильный результат для display % 1000 /100
Код: Выделить всё
12345 % 1000 /100 = 345 / 100 = 3Другое дело, что хороший компилятор может это упростить до display / 100 % 10
Код: Выделить всё
12345 / 100 % 10 = 123 % 10 = 3P.S. Но вообще, ранее приведённый код - плохой, так как в нём вычисления для каждого разряда разные:
Код: Выделить всё
PORTD = ~((SEGMENTE[display % 1000/100]));
PORTD = ~(SEGMENTE[display % 100/10]);
PORTD = ~(SEGMENTE[display % 10]);Код: Выделить всё
PORTD = ~(SEGMENTE[display % 10]); # разряд единиц
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд десятков
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд сотен
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд тысячP.P.S.
Вот пример такого подхода уменя - как-то делал по-быстрому по просьбе человека, который где-то разобыл табло для электронных очередей (с большими семисегментниками) и хотел сделать из этого часы.
Там ещё в этой функции и нули лишние не рисуются, если число маленькое получилось, и знак минуса поддерживается.
Последний раз редактировалось WiseLord Ср фев 14, 2024 20:58:36, всего редактировалось 3 раза.
Re: Вопросы по С/С++ (СИ)
[uquote="Bill_",url="/forum/viewtopic.php?p=4543375#p4543375"]Поэтому данное выражение компилятор вероятно сведёт к выражению display % 10. Или нет?[/uquote]Да ужж.... не думал, что на данном форуме так плохо с математикой начальных классов средней школы... печалька 
Добавлено after 8 minutes 5 seconds:
[uquote="WiseLord",url="/forum/viewtopic.php?p=4543527#p4543527"]Лучше выводить числа справа налево, тогда там для любого разряда нужно делать лишь %10 и /10, то есть, что-то вроде:
Такой подход и в цикл легко превратить, и работает с любым количеством разрядов...[/uquote]Ваш код тоже не ахти.
Зачем для каждого разряда 2 деления? Деление - плохая операция. Даже на тех МК, где она аппаратно есть, выполняется очень медленно.
Всё ведь просто:Всего по одному делению на разряд. На ARM такой код будет гораздо быстрее.
Добавлено after 8 minutes 5 seconds:
[uquote="WiseLord",url="/forum/viewtopic.php?p=4543527#p4543527"]Лучше выводить числа справа налево, тогда там для любого разряда нужно делать лишь %10 и /10, то есть, что-то вроде:
Код: Выделить всё
PORTD = ~(SEGMENTE[display % 10]); # разряд единиц
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд десятков
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд сотен
display /= 10;
PORTD = ~(SEGMENTE[display % 10]); # разряд тысячЗачем для каждого разряда 2 деления? Деление - плохая операция. Даже на тех МК, где она аппаратно есть, выполняется очень медленно.
Всё ведь просто:
Код: Выделить всё
uint i0 = display / 10;
uint digit0 = display - i0 * 10;
uint i1 = i0 / 10;
uint digit1 = i0 - i1 * 10;
...- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Потому что это:jcxz писал(а):Зачем для каждого разряда 2 деления? Деление - плохая операция. Даже на тех МК, где она аппаратно есть, выполняется очень медленно.
- легко читается и понимается
- может оптимизироваться компилятором так, что делений там и не будет.
- такой код вполне уместен при выводе результатов на экран, будучи вызываем один раз в главном цикле. В критичных местах вроде прерываний - да, делить лучше не стоит.
Например, анализируя листинг, я как-то видел что деление 8-битного числа 'num' на константу 10 компилятор обычно преобразует в умножение на 205 и сдвиг:
Код: Выделить всё
// Например, num = 234
// Написано программистом
digit = num % 10 # digit = 234 % 10 = 4
num /=10 # num = 234 / 10 = 23
// Оптимизировано компилятором
tmp = (num * 205) << 11; # tmp = (234 * 205) << 11 = 47970 << 11 = 23
digit = num - tpm * 10; # digit = 234 - 23 * 10 = 234 - 230 = 4
num = tmp; # num = 23Деление числа на 10 равносильно его умножению на 204.8 и последующему делению на 2048 (он же сдвиг вправо на 11 разрядов). А если умножать не на 204.8, а на 205 - результат для целых чисел будет эквивалентным, по крайней мере в диапазоне 0..255 (P.S. а на самом деле - даже в диапазоне 0..1028).
Для чисел большей разрядности можно тоже подобрать (и компиляторы это часто умеют) такие числа, которые будут давать правильный результат.
P.S.
Кстати, попробовал ваш совет применить в вышеуказанном проекте, и... фиаско:
"До" - размер бинарника прошивки 1290 байт:
Код: Выделить всё
for (i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot)
break;
ind[i] = num[number % 10];
number /= 10;
}Код: Выделить всё
for (i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot)
break;
uint16_t i10 = number / 10;
ind[i] = num[number - i10 * 10];
number = i10;
}
P.P.S.
Целочисленное деление на 10 вовсе не добавляет "ещё одно деление". Раз уж при вычислении остатка от деления число уже было один раз поделено на 10 (и промежуточный результат деления был помещён в какой-то регистр), второй раз комплиятор этого делать не будет, и num /= 10 сведётся просто к забиранию из этого регистра готового результата.
Re: Вопросы по С/С++ (СИ)
WiseLord, может, компактней будет использовать div_t - в этом случае, скорее всего, всё обернётся в функцию и её вызовы.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
WiseLord, код не оптимизируют по размеру бинарника. Надо листинг для целевой платформы смотреть.
Re: Вопросы по С/С++ (СИ)
[uquote="WiseLord",url="/forum/viewtopic.php?p=4543605#p4543605"]Кстати, попробовал ваш совет применить в вышеуказанном проекте, и... фиаско:
"До" - размер бинарника прошивки 1290 байт:
После - размер бинарника прошивки 1372 байта:
После "оптимизации" прошивка стала больше на 82 байта.[/uquote]Почти 1.5 КБ на таком простейшем коде??? Серьёзно???
Как вы такого добились?
Попробовал скомпилить в IAR:
Результаты:
1-й вариант:2-й:
Как видно - всего 22 байта как в 1-м так и во 2-м случае. Как у вас получилось почти 1.5 КБ - ума не приложу.
Да, в этом случае компилятор догадался, что команду UDIV можно использовать только одну. И в этом случае разницы между вариантами нет. Но компилятор не всегда такой догадливый. В более сложных функциях он не всегда догадывается до этого. И тогда вариант 2 получается и меньше и быстрее.
"До" - размер бинарника прошивки 1290 байт:
Код: Выделить всё
for (i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot)
break;
ind[i] = num[number % 10];
number /= 10;
}Код: Выделить всё
for (i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot)
break;
uint16_t i10 = number / 10;
ind[i] = num[number - i10 * 10];
number = i10;
}
Как вы такого добились?
Попробовал скомпилить в IAR:
Код: Выделить всё
enum {DIGITS = 6};
static u8 ind[DIGITS];
static u8 const num[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
#if 0
void f1(uint number, uint dot)
{
for (uint i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot) break;
ind[i] = num[number % 10];
number /= 10;
}
}
#else
void f2(uint number, uint dot)
{
for (uint i = 0; i < DIGITS; i++) {
if (number == 0 && i > dot) break;
uint i10 = number / 10;
ind[i] = num[number - i10 * 10];
number = i10;
}
}
#endif1-й вариант:
Код: Выделить всё
void f1(uint number, uint dot)
{
for (uint i = 0; i < DIGITS; i++) {
_Z2f1jj: (+1)
00000000 0x2200 MOVS R2,#+0
00000002 0x230A MOVS R3,#+10
if (number == 0 && i > dot) break;
??f1_0: (+1)
00000004 0xB908 CBNZ.N R0,??f1_1
00000006 0x4291 CMP R1,R2
00000008 0xD304 BCC.N ??f1_2
ind[i] = num[number % 10];
number /= 10;
}
??f1_1: (+1)
0000000A 0x1C52 ADDS R2,R2,#+1
0000000C 0x2A06 CMP R2,#+6
0000000E 0xFBB0 0xF0F3 UDIV R0,R0,R3
00000012 0xD3F7 BCC.N ??f1_0
}
??f1_2: (+1)
00000014 0x4770 BX LR ;; returnКод: Выделить всё
void f2(uint number, uint dot)
{
for (uint i = 0; i < DIGITS; i++) {
_Z2f2jj: (+1)
00000000 0x2200 MOVS R2,#+0
00000002 0x230A MOVS R3,#+10
if (number == 0 && i > dot) break;
??f2_0: (+1)
00000004 0xB908 CBNZ.N R0,??f2_1
00000006 0x4291 CMP R1,R2
00000008 0xD304 BCC.N ??f2_2
uint i10 = number / 10;
ind[i] = num[number - i10 * 10];
number = i10;
}
??f2_1: (+1)
0000000A 0x1C52 ADDS R2,R2,#+1
0000000C 0x2A06 CMP R2,#+6
0000000E 0xFBB0 0xF0F3 UDIV R0,R0,R3
00000012 0xD3F7 BCC.N ??f2_0
}
??f2_2: (+1)
00000014 0x4770 BX LR ;; return
Да, в этом случае компилятор догадался, что команду UDIV можно использовать только одну. И в этом случае разницы между вариантами нет. Но компилятор не всегда такой догадливый. В более сложных функциях он не всегда догадывается до этого. И тогда вариант 2 получается и меньше и быстрее.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
Пятничная затравка Код.
Для беззнаковыхПерегрузка для знаковых
Для беззнаковых
Код: Выделить всё
void Num2Segs(std::unsigned_integral auto number)
{
for(auto i=DIGITS; i; )
{
if(number || i==DIGITS)
{
auto dv = div(number,10);
ind[--i] = Dig2Seg[dv.rem];
number = dv.quot;
}
else ind[--i] = 0;
}
}Код: Выделить всё
void Num2Segs(std::signed_integral auto number)
{
for(auto &x : ind) x=0;
bool neg = number<0;
auto tmp = neg ? -number : number;
for(auto i=DIGITS; i>(neg?1:0); )
{
if(tmp || i==DIGITS)
{
auto dv = div(tmp,10);
tmp = dv.quot;
ind[--i] = Dig2Seg[dv.rem];
if(neg && (tmp==0 || i==1))
{
ind[--i]= Dig2Seg[10]; // минус
break;
}
}
else --i;
}
}Re: Вопросы по С/С++ (СИ)
[uquote="VladislavS",url="/forum/viewtopic.php?p=4544156#p4544156"]Пятничная затравка Код.
Для беззнаковых
...
Перегрузка для знаковых
...[/uquote]Ну всё - блоха подкована.
Лишь бы скакать после этого смогла.
Для беззнаковых
...
Перегрузка для знаковых
...[/uquote]Ну всё - блоха подкована.
Лишь бы скакать после этого смогла.
Последний раз редактировалось jcxz Пт фев 16, 2024 18:20:29, всего редактировалось 1 раз.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
Скорее воробьи постреляны.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Нет, конечно. Это целиком весь проект часов https://github.com/WiseLord/clock7segmjcxz писал(а):Почти 1.5 КБ на таком простейшем коде??? Серьёзно???![]()
![]()
![]()
Смотрите не на абсолютное значение, а на разницу.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Вопросы по С/С++ (СИ)
WiseLord, хотел посмотреть откуда 82 байта, а функция segmNum в коде вообще не используется.
Добавлено after 1 hour 13 minutes 40 seconds:
Забил функцию в Compiler Explorer. Было.
Немного поработал с типами. Стало.
Вот теперь можно попробовать разные варианты. Не забыть оптимизацию O2 и O3 попробовать - там интереснее.
Добавлено after 1 hour 13 minutes 40 seconds:
Забил функцию в Compiler Explorer. Было.
Немного поработал с типами. Стало.
Вот теперь можно попробовать разные варианты. Не забыть оптимизацию O2 и O3 попробовать - там интереснее.
