Перейти к содержанию
    

Почему для GCC следующий код в полном порядке?

25 minutes ago, jcxz said:

более читаем (менее громоздок)

скажите, какой параметр тут что означает прямо сходу, без ныряния в дебри документации:

draw(8, 0, 1, 100, true, false, false, false, false, false, false);

 

 

25 minutes ago, jcxz said:

2-й очевидно оптимальнее по результирующему коду (на ARM)

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, jcxz said:

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

один из вариантов:

display.drawRectangle(someRectangle);

someRectangle - это объект класса Rectangle (по ссылке &), который нужно заранее создать, способы разные: локально на время рисования, как параметр снаружи из другой функции и др.)

 

33 minutes ago, jcxz said:

графический контекст устройства вывода

"display" еще на этапе создания инициализации УЖЕ имеет все необходимые ресурсы для рисования (ссылку, например, на драйвер дисплея), поэтому передавать их в метод drawRectangle нет никакого смысла, это только загромождает код бессмысленным дублированием параметров

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я ранее писал, что ум (соображаловка) программиста должен быть гибким и живым. То есть, не действовать всегда по одному шаблону, а меняться, подстраиваться. Это к тому, что есть два варианта: передача длинного списка (в основном константных) параметров в виде структуры и передача параметров раздельно по значению. Каждый вариант хорош по-своему. В том же CubeHAL инициализующие параметры пердаются в структуре. Но вот в GUI динамически меняющиеся параметры предпочитают передавать отдельно. Например, ф-ция построения прямоугольника содержит координаты верхнего левого и нижнего правого углов и цвет "чернил", а так же ссылку на структуру описания графической плоскости, в которой будет вестись построение. Тут используются два метода совместно - как передача параметров координат раздельно (поскольку они меняются), так и передача ссылки (указателя) на структуру описания (поскольку оная не меняется). Почувствуйте, какгрицца, раздницу! 

В этом заключается гибкость мышления разработчика (программиста). Не кодописателя, а программиста. Разницу понимаете между этими словами? Вы сами об этом спрашивали, дескать, чем отличается разработчик (проектировщик) от кодера. Вот этим и отличается. Кодописатель умеет быстро тыкать клаву. Разработчик умеет гибко мыслить и применять инструменты независимо от числа цифр в них, потому что у него мозг так развит, что может запомнить более двух цифр. Ну и всегда на помощь приходит правильная IDE, показывающая все эти заморочки. Я выше скрин выложил - это только одна из плюшек. А еще при задержке мышки над функцией всплывает окошко с её содержимым, где можно просмотреть и пролистать всё, что находится в ней. Это просто правильные инструменты и они делают правильный "мёд"(С). 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не интересно - не читайте, никто не заставляет. Тут просто человеки рассказывают, что необязательно зацикливаться на одном единственном способе. Мышление разработчика (не кодировщика!) должно быть гибким, творческим, а память хорошей. "Чтобы оставаться на месте, нужно бежать вперед, а чтобы продвигаться, нужно бежать вдвое быстрее"(С)Кто-то из древних. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Forger сказал:

один из вариантов:

display.drawRectangle(someRectangle);

someRectangle - это объект класса Rectangle (по ссылке &), который нужно заранее создать, способы разные: локально на время рисования, как параметр снаружи из другой функции и др.)

..... и получить более громозкий, менее читаемый и более медленный код. Спасибо, не надо.

1 час назад, Forger сказал:

 

"display" еще на этапе создания инициализации УЖЕ имеет все необходимые ресурсы для рисования (ссылку, например, на драйвер дисплея), поэтому передавать их в метод drawRectangle нет никакого смысла, это только загромождает код бессмысленным дублированием параметров

Здесь вообще не понял о чём речь...... Откуда вы взяли, что там какой-то "display"?

Пример тот был - про общий вид рисования прямоугольника в разных графических API. Например в одном из моих устройств, в качестве такого контекста мог выступать: либо контекст физически подключенного к МК LCD; либо контекст виртуального LCD (в реальности являющегося частью окна приложения на подключенном к устройству ПК (через USB)). И как прикажете определять - куда этот прямоугольник рисовать (в физический LCD или виртуальный) если не передавать указатель на контекст?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Плюсую, поскольку графика может рисоваться не только непосредственно на дисплее, но и просто где-то в ОЗУ, являясь частью изображения, которое затем будет вставлено в другую часть, и только потом будет отображено на дисплее. Это - нормальная практика.

И опять же, есть два способа - создать объект класса, в котором будут прописаны все эти линии, квадратики, кружочки, ромбики, перенос битмапов. Или же иметь статические методы построения всей этой лабуды, в которые будет приниматься объект класса графической области с её параметрами. Однако, внедрять в эту же кучу драйвер дисплея - нууу так себе затея, поскольку таких графических областей может быть несколько, и они описывают элементы, из которых составляется полное изображение. И чтож теперь, прикажете в каждый этот элемент внедрять драйвер дисплея? Ну это так, для размышления на тему...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гуры программирования вроде Б.Страуструпа говорят, что хороший стиль выполнения фунций таков, что аргументов функций не должно быть много -- лучше всего один-два, три тоже приемлемо в обоснованных случаях, особенно, если это редкоиспользуемый аргумент со значением по умолчанию. Если надо больше передавать, то упаковывать в объект структуры или класса и передавать по констатнтой ссылке. Размер функции тоже не должен быть большим -- функции на пять экранов -- плохо. Полтора экрана максимум. Если выходит больше -- то рефакторинг с разбиением на функции (накладные на их вызов можно нивелировать, сделав их встраиваемыми). Такой стиль написания кода значительно облегчает и разработку, и чтение, и сопровождение.

Если много параметров для передачи надо засунуть в вызов, то требуются именованные агрументы. Например, в Verilog/SystemVerilog синтаксис модуля похож на Сишный, и там обычно много портов (аргументов -- по аналогии с функциями), такова природа языка. И там тоже можно передавать значения сигналов, соблюдая порядок, но если их больше двух, то повсеместно испольют именованные:

fifo_sc_m
#(
    .DATA_ITEM_TYPE ( pkt_tag_t              ),
    .DEPTH          ( ZONE_PROPS_QUEUE_DEPTH ),
    .MEMTYPE        ( "lutram"               )
)
pkt_tag_queue
(
    .clk         ( clk                   ),
    .rst         ( rst                   ),
    .tail        ( pkt_tag_q.tail        ),
    .head        ( pkt_tag_q.head        ),
    .push        ( pkt_tag_q.push        ),
    .pop         ( pkt_tag_q.pop         ),
    .full        ( pkt_tag_q.full        ),
    .empty       ( pkt_tag_q.empty       ),
    .wr_rst_busy ( pkt_tag_q.wr_rst_busy ),
    .rd_rst_busy ( pkt_tag_q.rd_rst_busy )
);

Это введно в язык (Verolig) изначально, т.к. сразу были понятны проблемы позиционной передачи портов, когда их много. Получается по сути тот же вариант, что выше привёл @Forger со упаковкой агрументов в структуру. Различаемость аргументов при чтении кода, когда их много, крайне важна. Иначе получается write-only код. 

Спорить, доказывать никому ничего не буду. Это мнение опытных в Computer Science людей (кроме Б.Страуструпа встречал подобные рекомендации и от других гур, но навскидку не вспомню, да и не суть). И я с ним согласен -- многолетний опыт только подтверждает это..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Берем абстрактный пример:

void Line(coord_t start, int len, int color, param_t *window); 
...
Line({10, 20}, 50, RED, &win);
Line({75, a1}, -15, GREEN, &win);
Line({a1, b1}, 77, BLUE, &win);

И параметров немного, и понятно всё, и компактно.

Тот же самый пример, но с одним параметром в виде упакованной структуры:

param.coord.x = 10;
param.ccord.y = 20;
param.len = 50;
raram.color = RED;
param.window = &win;
Line(&param);

param.coord.x = 75;
param.coord.y = a1;
param.len = -15;
param.color = GREEN;
Line(&param);

param,coord.x = a1;
param.coodr.y = b1;
param.len = 77;
param,color = BLUE;
Line(&param)

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

Почему в то время этот, как ево, Страус... (я знаю, кто это такой!) топил за один параметр в виде указателя на структуру. Да потому, что в то время вычислительные ядра имели мало регистров, а все эти параметры передаются через регистры. И ясен пень, чем больше параметров, тем больше регистров задйствуются. Но в современном железе - не повод отказываться от 3-4-5 параметров, если так будет лучше. И повторюсь, во всем должен быть разумный подход! И мышление программиста (не кодописателя) должно быть гибким. Тот или иной подход применяется конкретно по обстановке. Так понятнее?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 12/5/2023 at 6:44 AM, dxp said:

многолетний опыт только подтверждает это..

тоже пришел к такому же выводу, не сразу конечно

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пример выше я привел - два варианта. Если в первом варианте кодописателю сложно запомнить три циферки, можно вначале снабдить всего одним комментом // ({x, y}, len, color, &win) и построить пийсят линий подряд. Во втором варианте записи эти пийсят линий займут манускрипт на пять экранов длиной и не будут иметь никакого профита хоть визуально, хоть программно.  С этим даже этот ваш Страус... согласился бы! Хоть он и не является родоначальником языка, он всего лишь переработал и добавил расширенную надстройку к первому варианту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 05.12.2023 в 05:44, dxp сказал:

Гуры программирования вроде Б.Страуструпа говорят, что хороший стиль выполнения фунций таков, что аргументов функций не должно быть много -- лучше всего один-два, три тоже приемлемо в обоснованных случаях, особенно, если это редкоиспользуемый аргумент со значением по умолчанию. Если надо больше передавать, то упаковывать в объект структуры или класса и передавать по констатнтой ссылке.

Т.е. - одно полотенце из аргументов меняем на ещё бОльшее полотенце (из теперь уже заполнения членов структуры) и это полотенце вам почему-то нравится больше???

Не можете запомнить названия аргументов функции? Воспользуйтесь комментариями. Как уже заметили выше.

Ну или переходите на Python - там можно именовать аргументы функции.

 

PS: Во всякие громкие имена тыкать пальцем не надо - можно найти кучу противоположных, не менее авторитетных мнений. А самый главный авторитет это - практика. А она однозначно говорит, что: Передавать через структуры/классы то, что можно передать через регистры - это снижать эффективность кода. Тем более в embedded, с его ограничениями ресурсов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 12/5/2023 at 4:44 AM, dxp said:

Это введно в язык (Verolig) изначально

У верилога с разнообразием типов изначально было довольно бедно и перепутать местами clk и rst у модуля с парой десятков аргументов несколько проще. В том же С компилятор не даст поменять местами double и указатель на строку.

11 hours ago, EdgeAligned said:

Во втором варианте записи эти пийсят линий займут манускрипт на пять экранов длиной

С (в отличии от плюсов) вроде умеет в человеческую инициализацию структур

Line((param_t){{75, a1}, .len = -15, .color = GREEN, win});

 

5 hours ago, jcxz said:

Передавать через структуры/классы то, что можно передать через регистры - это снижать эффективность кода. Тем более в embedded, с его ограничениями ресурсов.

Отчасти да конечно, но в embedded с его ограничениями ресурсов обычно больше четырёх параметров через регистры всё равно не передаётся, (да и не в ембеддед, винды на x64 тоже только 4 аргумента через регистры передают).

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 минуты назад, _pv сказал:

Отчасти да конечно, но в embedded с его ограничениями ресурсов обычно больше четырёх параметров через регистры всё равно не передаётся, (да и не в ембеддед, винды на x64 тоже только 4 аргумента через регистры передают).

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

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

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

+1

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

И даже если надо мало аргументо передавать - все равно рулят. Маленькие структуры тож в регистрах неплохо передаются.

А когда надо возвращать много параметров в результатах - тока они и справятся

Изменено пользователем AlexRayne

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, _pv сказал:

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

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

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

1 час назад, _pv сказал:

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

Как вы так пишете код, что у вас так часто используются локальные переменные на стеке? - это вопрос к вашему стилю программирования и к ключам оптимизации компилятора.

А также к умению:

В 05.12.2023 в 05:44, dxp сказал:

то рефакторинг с разбиением на функции

1 час назад, _pv сказал:

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

"Читаемость" - понятие субъективное. Как уже выяснили. Имхо - многострочные портянки с заполнением членов структур - гораздо менее читаемые.

52 минуты назад, AlexRayne сказал:

почемут люди думают что передавать в параметрах аргументы бесплатно - а сколько кода тратится на них не учитывают.

Здесь вообще непонятно - о чём речь?? :wacko2:

52 минуты назад, AlexRayne сказал:

Если вложеность вызовов процедур больше 1го, или надо много раз передаватть одни и теже параметры разным функциям - структуры рулят.

1. А если не те же? А если вызываемая функция должна изменить какой-то аргумент, прежде чем передать его глубже? Не подумали? И сколько тогда потратите ресурсов (тактов и размера стека) на копирование одной структуры в другую?

2. А если далее вглубь цепочки вызовов надо передать не все аргументы, а на один меньше? Опять копировать???  :dash2:

Так "сколько кода тратится" на бездумное следование вашему методу?

 

Я могу привести множество примеров, когда ваш подход приведёт не то, что к потере нескольких тактов, а к очень существенному перерасходу ресурсов.

С таким подходом и рождаются программы-монстры, сжирающие все ресурсы даже современных CPU на несложных задачах...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...