LINUX.ORG.RU
ГолосованияГолосования (не подтверждено)

Какой кусок исходного кода на Си Вам кажется более красивым (см. подробности)

 , ,


0

2

первый вариант:

a[0] = get_data(0);
a[1] = get_data(1);
a[2] = get_data(2);
a[3] = get_data_3();
a[4] = get_data(4);
a[5] = get_data_5();

второй вариант:

for(int i = 0; i < sizeof(a)/sizeof(a[0]); i++) {
  switch(i) {
    case 3: a[i] = get_data_3(); break;
    case 5: a[i] = get_data_5(); break;
    default: a[i] = get_data(i); 
  }
}
★★★★★

Последнее исправление: Virtuos86 (всего исправлений: 2)

второй, только если исправить хардкод с i<6 на вычисление длины массива

Deleted
()

Первый вариант может быть полезен, если код активно меняется (поскольку так быстрее делать правки), второй для окончательного варианта. И конечно избавиться от magic numbers во втором

mittorn ★★★★★
()
Ответ на: комментарий от mittorn

второй для окончательного варианта

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

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Когда приводится пример обычно предполагается что его объём будет меняться. С ростом объёма второй случай компактнее окажется. Да и где же второй случай дольше читается? Программист for + switch сразу выделит и всё внимание будет на внутреннем блоке, который хоть и больше по символам, по смыслу меньше - тут сразу видно что для 5 и 3 выполняются специальные функции, а для остальных общая. Вариантов case всего 3, в первом случае надо читать и сравнивать все 6 вариантов «а нет ли там какого-то подвоха ещё?» т.к в 3 и 5 он есть

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 1)
Ответ на: комментарий от mittorn

Когда приводится пример обычно предполагается что его объём будет меняться. С ростом объёма второй случай компактнее окажется.

С ростом объёма количество особых случае тоже увеличится. И логика может усложниться, Будет что-то вроде

...
a[11] = get_data_11_13(1, 1, 5);
a[12] = get_data_11_13(1, 2, 6);
a[13] = get_data_11_13(1, 2, 7);
...
case 11:
case 12:
case 13:
  a[i] = get_data_11_13(1, (i==11)?1:2, i-6);

Программист for + switch сразу выделит и всё внимание будет на внутреннем блоке, который хоть и больше по символам, по смыслу меньше - тут сразу видно что для 5 и 3 выполняются специальные функции, а для остальных общая.

Чтобы выяснить, что попало в a[4] нужно прочитать все варианты case. А в первом варианте только одну строку с "a[4] = ".

P.S. Хотелось бы, чтобы это всё-таки подтвердили на голосование.

monk ★★★★★
() автор топика

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

второй подход более удобный для эксплуатации в динамично меняющемся коде (входных данных).

Deleted
()
Последнее исправление: Deleted (всего исправлений: 2)

cc Эскобар.c

Что значит «более красивым»? Ты код для выставки пишешь? Это какой-то новый вид искусства?

mord0d ★★★★★
()
Последнее исправление: mord0d (всего исправлений: 1)
Ответ на: комментарий от rsync

Это понимать как «сейчас первый вариант наилучший»? Или, что у тебя есть вариант «втрое короче»? Если есть, покажи.

monk ★★★★★
() автор топика
Ответ на: комментарий от mord0d

Ты код для выставки пишешь? Это какой-то новый вид искусства?

Если код пишется в открытый проект, то он является литературным произведением, которое регулярно критикуют эксперты с ЛОРа.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Если код пишется в открытый проект

То в этом открытом проекте есть правила оформления кода, которые покрывают всё.

регулярно критикуют эксперты с ЛОРа.

ЛОР давно пробил дно. У большей части личной жизни ещё нет, у остальных уже нет, вот они и критикуют всё, что на глаза попадётся. Не сомневаюсь, они будут критиковать и позу, в которой ты срёшь, и бабу, с которой ты спишь («ты» здесь образное).

mord0d ★★★★★
()

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

alienclaster ★★★
()

Первый конечно же. Второй на пяти элементах - оверинжиниринг.

goingUp ★★★★★
()
Ответ на: комментарий от monk

А как бы ты писал такой код, если эти оба плохи?

Зависит от цели. Примеры, когда тот или иной вариант плох, в треде уже обсосали. Идеального Универсального решения нет, иначе не было бы таких опросов и прочих тредов на тему «покритикуйте мой говнокод».

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Универсального решения нет, иначе не было бы таких опросов и прочих тредов на тему «покритикуйте мой говнокод».

Тут чаще треды на тему «ааа, я нашёл говнокод». Вот реализацию FSM через switch критикуют: К юбилею VVVVVV автор открыл исходники (комментарий)

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

Вообще вопрос возник из обсуждения «китайского кода». Мол, китайцы не умеют писать абстракции, поэтому пишут кучу копипасты. Моя точка зрения: в китайском языке нет запрета на повторение, поэтому нет инстинктивного отторжения повторяющегося кода. А с другой стороны, для кода и инструкций я предпочитаю китайский стиль. В китайской инструкции если есть «нажмите верхнюю левую кнопку приборной панели», то оно так и будет во всей инструкции, а не преобразуется к концу в «нажмите верхнюю левую кнопку», «нажмите эту кнопку», «выполните нажатие», «нажмите», … и если читаешь, скажем, 42 пункт инструкции, то чтобы его понять, приходится просматривать предыдущие 41, так как контекст не очевиден.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

реализацию FSM через switch критикуют

Автор, вроде, оговорился, что он не программист.

Моя точка зрения: в китайском языке нет запрета на повторение, поэтому нет инстинктивного отторжения повторяющегося кода.

Верно, язык формирует мышление.

А с другой стороны, для кода и инструкций я предпочитаю китайский стиль. В китайской инструкции если есть «нажмите верхнюю левую кнопку приборной панели», то оно так и будет во всей инструкции, а не преобразуется к концу в «нажмите верхнюю левую кнопку», «нажмите эту кнопку», «выполните нажатие», «нажмите», … и если читаешь, скажем, 42 пункт инструкции, то чтобы его понять, приходится просматривать предыдущие 41, так как контекст не очевиден.

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

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

а не преобразуется к концу

Когда инструкция является просто порядком действий, то это ещё можно стерпеть (не успеешь потерять контекст), но когда ты читаешь книгу (особенно обучающую), и изначально "синий" к концу, через полтыщи-тыщу страниц, становится "красным", пройдя всю градацию…

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Автор, вроде, оговорился, что он не программист.

Это понятно. Но единственное реальное улучшение его кода, которое можно сделать — заменить номера состояний на имена констант. А любителям красоты надо разорвать машину состояний на множество отдельных объектов, в каждом из которых будет своё состояние.

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

Не только славянских. В английском то же самое. arguments list is a list of strings → … this list … → … the list ….

В идеале, конечно, писать документацию на английском

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

Но для этого надо сначала всех заставить выучить китайский…

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

arguments list is a list of strings → … this list … → … the list ….

Только если на протяжении всего текста идёт упоминание единственного списка. Хотя может и встречается отвал контекста в процессе, человеческий фактор никто не отменял.

Не только славянских.

Я же не писал, что только в славянских, но в славянских это встречается чаще.

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

Ага, и запись сверху вниз…

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

Но для этого надо сначала всех заставить выучить китайский…

Я, пожалуй, воздержусь. ☺

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Только если на протяжении всего текста идёт упоминание единственного списка.

Но вот пример со словом elements: https://docs.python.org/3/howto/functional.html?highlight=list#creating-new-iterators

Раздел «Grouping elements» подразумевает под словом elements итерируемые элементы, а в фразах «provided element» и «little functions that act as predicates or that combine elements in some way» уже под словом element(s) подразумеваются аргументы функции.

Не говоря уж про кучу синонимов: «iterable», «iterator», «stream», «elements».

Для китайца или математика это полный бардак.

Я, пожалуй, воздержусь. ☺

Смайлики ведь выучил ☺. Китайский почти такой же, только «смайликов» побольше и они чуть разнообразнее.

Ага, и запись сверху вниз…

Кстати, двумерная запись формул математики и химии — величайшее изобретение. Жаль, в программировании почти не прижилось.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Для китайца или математика это полный бардак.

Хаос есть высшая форма порядка, которую человеку понять не дано.

Смайлики ведь выучил ☺.

Я использую только один, и только на ЛОРе. Emoji у меня вообще не отображаются.

Китайский почти такой же

Далеко нет.

чуть разнообразнее

Традиционный китайский чуть более разнообразен, чем «чуть разнообразнее».

Кстати, двумерная запись формул математики и химии — величайшее изобретение.

Но оно требует соответствующего "холста" для записи. Мне доставляет боль видеть математические формулы (особенно если они не помещаются на одну страницу) в печатных книгах (или в формате с фиксированным размером страницы, например в PDF).

Жаль, в программировании почти не прижилось.

Раз уж дошло до математики… мне нравится как это обыгрывается в APL.

mord0d ★★★★★
()

Если прототипы функций одинаковы, то делается массив с указателями на функции (funcs) и цикл.

typedef int (*switch_fn_t)(int param);

switch_fn_t funcs[] = { get_data, get_data, get_data,  get_data_3 ... };
for(int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
        a[i] = funcs[i](i)

А так, пока 1й вариант все-таки понятнее. Но если он будет всё длиннее и длиннее….

P.S. Вижу, что прототипы НЕ одинаковы. Тогда надо макрос делать ;) Ибо основное уродство в явно заданных индексах 1го варианта. Тогда какой-нибудь i++ в макросе при присвоении может скрасить картину….

Вообще, непонятно как потом массив a используется. Может быть вообще индекс дб enum… Если потом эти значения выборочно извлекаются….

gloomy ★★
()
Последнее исправление: gloomy (всего исправлений: 2)
Ответ на: комментарий от gloomy

Вообще, непонятно как потом массив a используется. Может быть вообще индекс дб enum… Если потом эти значения выборочно извлекаются….

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

Извлекаться могут выборочно, но у датчика нет имени, только номер. Можно, конечно, заменить на a[SENSOR_1] = get_data(SENSOR_1);, a[SENSOR_2] = get_data(SENSOR_2);, … Это будет лучше?

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

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

Ну или выкинешь ты часть сенсоров, все индексы поедут. А с енумом нет. Сенсор 12 останется таким в коде не зависимо от индекса в массиве…

gloomy ★★
()
Последнее исправление: gloomy (всего исправлений: 2)
Ответ на: комментарий от gloomy

Согласен. Также явное указание, что массив не совсем однородный.

В минусе — лишних N строк в программе.

monk ★★★★★
() автор топика
18 марта 2020 г.
#include <stdio.h>

unsigned int get_data_3(void)
{
    return 3;
}
unsigned int get_data_5(void)
{
    return 5;
}
unsigned int get_data(unsigned int id)
{
    return id;
}

void handle_data(unsigned int a_data[],size_t size,unsigned int (*a_get[])())
{
    for (size_t i = 0; i < size;i++)
    {
        a_data[i] = (a_get[i]) ? a_get[i](i): ((unsigned int)0)-1;
    }
}

int main(int argc, char *argv[])
{
    //set data storage size
    enum{ A_SIZE = 5+1 };
    //make data storage
    unsigned int a_dat[A_SIZE];
    //register data getters
    unsigned int (*a_get[A_SIZE])() =
    {
        [0] = get_data,
        [1] = get_data,
        [2] = get_data,
        [3] = get_data_3,
        [4] = get_data,
        [5] = get_data_5
    };
    //handle data
    handle_data(a_dat,A_SIZE,a_get);
    //debug
    for (int i = 0; i < A_SIZE ; printf("%u\n",a_dat[i++]));

    return 0;
}
LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от monk

Всё зависит от случая, если размер a_dat имеет склонность меняться, если все его значения всегда нужно обновлять, если я явно хочу вводить соотвецтвие данных и откуда они получаются, если назначение соотвецтвия данных и получения их где то наверху один раз, а само заполнение многократно происходит где то там внизу. Если некоторых обработчиков для получения данных может не быть и вместо них будет NULL, если каждое следующее заполнение зависит от состояния предыдущих тут надо в get_data передавать ещё указатель тогда на a_dat. Я бы выбрал Первый твой вариант если a_dat размером в максимум 200 ячеек (клавиатура там или подобное) второй вариант если их тупа многа, но первый вариант если их даже тупа многа, но надо навешивать логику потом. Свой вариант если я бы хотел чисто для себя разделить обработку и назначение обработчиков, но только в том случае если это имеет тенденцию меняться. Так что это под каким углом смотреть, под одним это сарказм, под другим это логично, под третьим это глупо.

И да я не программист если чаво ^.^ можешь меня не слушать =)

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Просто семантически твой вариант отличается от первого моего только заменой построчно

a[0] = get_data(0);
a[1] = get_data(1);
a[2] = get_data(2);
a[3] = get_data_3();
a[4] = get_data(4);
a[5] = get_data_5();

на

        [0] = get_data,
        [1] = get_data,
        [2] = get_data,
        [3] = get_data_3,
        [4] = get_data,
        [5] = get_data_5

и добавлением дюжины строк.

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

a[0] = get_data(0);
a[1] = get_data(1);
a[2] = get_data(8); // заменили порт
a[3] = get_data_3();
a[4] = get_data(4);
a[5] = get_data_5();

? Придётся добавлять get_data_2() { return get_data(8); }

Или если добавится

...
a[11] = get_data_11_13(1, 1, 5);
a[12] = get_data_11_13(1, 2, 6);
a[13] = get_data_11_13(1, 2, 7);
...

По сравнению со вторым вариантом намного больше слов.

Единственный плюс твоего варианта: он соответствует некому паттерну. Но тогда самый красивый вариант реализации FizzBuzz – это https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition . Там есть все паттерны, которые потенциально можно было бы использовать.

monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Почему работает a_get[i](i) ???

В типе стоит unsigned int (*a_get[])(). То есть a_get[i] должен иметь тип unsigned int (*f)(). Но передача ему параметров проходит. Более того, параметр передаётся даже в get_data_3(void) без каких-либо предупреждений.

Разве Си не типизированный язык?

monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

паттерны

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

А так то что ты выше сказал… Да косяки есть, но либо я недопонял либо в ТЗ есть UB если теперь в блок данных не привязан к процедуре получения данных (или источнику посредством процедуры) это уже чуть другое. Ща попробую что-то родить по приколу под такие условия, пока у меня супчик варится =)

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от monk

Почему работает a_geti ???

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

Разве Си не типизированный язык?

Да но я объявил как (*a_get[])() (*a_get[A_SIZE])() то есть вот этим -> () в конце сказал «не контролируй аргументы я сам решу какие они» считай явно привёл.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

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

Круче только нумерация времени в AM/PM: 10AM 11AM 12PM 1PM 2PM … 11PM 12AM 1AM …

monk ★★★★★
() автор топика
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от monk

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

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

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от monk

Круче только нумерация времени в AM/PM: 10AM 11AM 12PM 1PM 2PM … 11PM 12AM 1AM …

Да неее, всё нормально.

Когда я в указателе на функцию говорю (void) значит нет аргументов, тоесть

void foo(int x) // это спецификатор функции! Он строгий и однозначный!
{
   printf("%d\n",x);
}

//Указатель на функцию который ТОЧНО  ничего не возвращает и ТОЧНО ничего не принимает
void (*func)(void) = foo; //ошибка! конпелятор по лица скалкой даёт
func();// до сюда не дойдём )))))))

//Указатель на функцию который ТОЧНО  ничего не возвращает и ХЗ принимает ли что
void (*func)() = foo; // всё ок

//важно в указателе мы говорим указывая пустые аргументы что аргументы **НЕКОНТРОЛИРУЮТСЯ** а не то что их нет, если их нет то мы говорим явно `(void)` иначе говорим `()` ==  не занаем, поэтому такую функцию можно
func(); // хоть так
func(100); // хоть сяк

//А во так уже нельзя. поэтому никакого отношения к переменным количествам аргументов пустые скобки не имеют
func(100,100);

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 3)
Ответ на: комментарий от LINUX-ORG-RU

//А во так уже нельзя. поэтому никакого отношения к переменным количествам аргументов пустые скобки не имеют

$ cat test.c
#include <stdio.h>

void foo(int x) // это спецификатор функции! Он строгий и однозначный!
{
   printf("%d\n",x);
}

int main(int argc, char *argv[])
{
    void (*func)() = foo;
    func(100,100);
    func('c', '0', "ok");
    return 0;
}
$ gcc -Wall test.c
$ ./a.out
100
99
monk ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Всё верно думал

Неверно. Вот это компилируется:

#include <stdio.h>

void foo() // это спецификатор функции!
{
   printf("%d\n",10);
}

int main(int argc, char *argv[])
{
    foo(100,100);
    foo('c', '0', "ok");
    return 0;
}
monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Да, я лох. А лох я потому что спутал всплывшие в памяти ошибки clang с тем что сказал строками ранее сам же

а не то что их нет, если их нет то мы говорим явно (void) иначе говорим () == не занаем, поэтому такую функцию можно

если их нет то мы говорим явно (void) иначе говорим () == не занаем

Но, да к слову gcc и clang тут ведут себя по разному.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от monk

Верно, потому что я лох , читай выше =) Тут та же самая ситуация с с пустым (). Если сама реализация функции () то аргументы один хрен не получить. Не ну наверное можно жопу вывернуть на ружу. Но. Это уже извращения. Игнорировать аргументы, легко. Поучать когда их как бы нет не особо.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от monk

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

Короче я до конца так и не понял что именно надо, ну вот ещё родил гибрид тогда уж чё ))0

Вместо индексов идентификаторы, что бы можно было в нужной последовательности опрашивать, а не всегда по порядку. Если есть разные кейсы по всяким соотвецтвиям портов и значений от них получаемых то проще описать несколько массивов структур t_pin_data и просто пускать в дело конкретно нужный в данной ситуации. Ой короче не знаю. Если как я понял у нас есть некие источники данных которые вызываются по разному, но однотипно, и надо просто иногда менять для определённых данных определённые функции, на сами данные удобно повесить строгое id как имя, меняется лишь механизм получения данных и всё. Если так то так норм. Если функции получения данных воообще разные от слова совсем, то уже другой огород. Ну ладно. =)

#include <stdio.h>

//--------------------------------------------------
// Мусор - где то у тебя в программе он тоже будет
//--------------------------------------------------
int get_data(int a){ printf("get_data(%d)\n",a);
return a;}
int get_data_3(){ printf("get_data_3()\n");
return 3;}
int get_data_5(){ printf("get_data_5()\n");
return 5;}
int get_data_11_13(int a,int b,int c){ printf("get_data_11_13(%d,%d,%d)\n",a,b,c);
return a+b+c;}
//-------------------------------------------------

    enum 
    {
        PINS_NUM = 100, //num data
        PINS_ARG = 11 , //max func args
        NO_DATA  = -1 , //end data marker
        THE_END  = -1 , //end of data
    };

    struct t_pin_data
    {
        const long long int id;     //data id
        int handler_args[PINS_ARG]; //data handler args
        int (*handler) () ;         //data handler
        long long int data;         //data cell
    };

    void update_data(struct t_pin_data  data[PINS_NUM])
    {
        printf("-------------------------------\n");
        for (int i = 0; data[i].id != THE_END ; ++i)
        {
            switch(data[i].id)
            {
                /*Особые случаи*/
                case 28:
                {
                    data[i].data = data[i].handler(data[i].id);
                }break;

                case 42:
                {
                    data[i].data = data[i].handler(data[i].id);
                }break;

                /*Обычные случаи*/
                default:
                {
                    if(data[i].handler)
                    {
                        data[i].data = 
                        data[i].handler(data[i].handler_args[0],
                                        data[i].handler_args[1],
                                        data[i].handler_args[2],
                                        data[i].handler_args[3],
                                        data[i].handler_args[4],
                                        data[i].handler_args[5],
                                        data[i].handler_args[6],
                                        data[i].handler_args[7],
                                        data[i].handler_args[8],
                                        data[i].handler_args[9],
                                        data[i].handler_args[10]);
                    }
                }break;
            }
        }
    }

int main(int argc, char *argv[])
{
    //create data + handler
    struct t_pin_data pin_data[PINS_NUM] = 
    {
      /*id   args     handler          data     */
        {0,  {0}     ,get_data,        NO_DATA   },
        {1,  {1}     ,get_data,        NO_DATA   },
        {2,  {2}     ,get_data,        NO_DATA   },
        {99, {99}    ,get_data,        NO_DATA   },
        {3,  {3}     ,get_data_3,      NO_DATA   },
        {4,  {4}     ,get_data_5,      NO_DATA   },
        {5,  {5}     ,get_data,        NO_DATA   },
        {6,  {6}     ,get_data,        NO_DATA   },
        {7,  {7}     ,get_data,        NO_DATA   },
        {28, {28}    ,get_data,        NO_DATA   },
        {8,  {8}     ,get_data,        NO_DATA   },
        {9,  {9}     ,get_data,        NO_DATA   },
        {10, {1,1,1} ,get_data_11_13,  NO_DATA   },
        {11, {1,2,6} ,get_data_11_13,  NO_DATA   },
        {12, {1,2,7} ,get_data_11_13,  NO_DATA   },
        {13, {13}    ,get_data,        NO_DATA   },
        {42, {42}    ,get_data,        NO_DATA   },
        {66, {66}    ,get_data,        NO_DATA   },
        //-------------------------------------------
        {THE_END},
    };


    update_data(pin_data);

    printf("------------------------------\n");
    for (int i = 0; pin_data[i].id != THE_END; ++i)
    {
        printf(">> id=%-2lld data=%-2lld\n",pin_data[i].id,pin_data[i].data);
    }

    return 0;
}


dron@gnu:~$ gcc -Werror -Wall -pedantic  gg.c 
dron@gnu:~$ ./a.out 
-------------------------------
get_data(0)
get_data(1)
get_data(2)
get_data(99)
get_data_3()
get_data_5()
get_data(5)
get_data(6)
get_data(7)
get_data(28)
get_data(8)
get_data(9)
get_data_11_13(1,1,1)
get_data_11_13(1,2,6)
get_data_11_13(1,2,7)
get_data(13)
get_data(42)
get_data(66)
------------------------------
>> id=0  data=0 
>> id=1  data=1 
>> id=2  data=2 
>> id=99 data=99
>> id=3  data=3 
>> id=4  data=5 
>> id=5  data=5 
>> id=6  data=6 
>> id=7  data=7 
>> id=28 data=28
>> id=8  data=8 
>> id=9  data=9 
>> id=10 data=3 
>> id=11 data=9 
>> id=12 data=10
>> id=13 data=13
>> id=42 data=42
>> id=66 data=66
dron@gnu:~$ 


LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 3)

struct t_pin_data pin_data[PINS_NUM]

Жесть. Ещё пару итераций и в программе будет полноценный интерпретатор лиспа. Всю логику данного куска уже можно менять в любой момент не прерывая программу.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Ну так ты сказал, функции меняются, денные меняются, стабильны только места куда писать. :3 Ждём дядек которые ща в три строчки код на все случаи жизни покажут в для данной задачи. М ы как читнём это поссым кипятком и познаем Дзен ))))0

Всю логику данного куска уже можно менять в любой момент не прерывая программу.

Да можно и кодогерерацию логики делать не прерывая программу запилив Jit в ещё несколько строк ))))))))))))))))))))))))))))))))))))))))))))))))))) https://eli.thegreenplace.net/2013/11/05/how-to-jit-an-introduction

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>


// Allocates RWX memory of given size and returns a pointer to it. On failure,
// prints out the error and returns NULL.
void* alloc_executable_memory(size_t size) {
  void* ptr = mmap(0, size,
                   PROT_READ | PROT_WRITE | PROT_EXEC,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (ptr == (void*)-1) {
    perror("mmap");
    return NULL;
  }
  return ptr;
}

void emit_code_into_memory(unsigned char* m) {
  unsigned char code[] = {
    0x48, 0x89, 0xf8,                   // mov %rdi, %rax
    0x48, 0x83, 0xc0, 0x04,             // add $4, %rax
    0xc3                                // ret
  };
  memcpy(m, code, sizeof(code));
}

const size_t SIZE = 1024;
typedef long (*JittedFunc)(long);

// Allocates RWX memory directly.
void run_from_rwx() {
  void* m = alloc_executable_memory(SIZE);
  emit_code_into_memory(m);

  JittedFunc func = m;
  int result = func(2);
  printf("result = %d\n", result);
}

int main(int argc, char *argv[])
{
    run_from_rwx();
    return 0;
}

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Ну так ты сказал, функции меняются, денные меняются, стабильны только места куда писать

Я же не подразумевал, что всё это меняется прямо во время выполнения программы. Решение красивое, мне нравится.

monk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.