Skip to content

Instantly share code, notes, and snippets.

@ramntry
Last active December 15, 2015 01:29
Show Gist options
  • Save ramntry/5180798 to your computer and use it in GitHub Desktop.
Save ramntry/5180798 to your computer and use it in GitHub Desktop.
true C style sample :)
#include <stdlib.h>
#include <stdio.h>
#define NUMOF_ACTIONS 16
struct action {
void *(*a_action)(void *);
void *a_arg_vp;
void *a_res_vp;
struct action *a_next_p;
};
static struct action actions[NUMOF_ACTIONS];
static struct action *free_action;
void init_actions(void)
{
int i;
for (i = 0; i < NUMOF_ACTIONS - 1; ++i) {
actions[i].a_next_p = &actions[i + 1];
}
free_action = &actions[0];
}
#define init_act_list(list) *(list) = NULL
void append_action(struct action **action_list, void *(*action)(void *), void *arg)
{
struct action *next_free_action;
if (!free_action) {
fprintf(stderr, "actions pool overflow\n");
exit(EXIT_FAILURE);
}
next_free_action = free_action;
free_action = free_action->a_next_p;
while (*action_list)
action_list = &(*action_list)->a_next_p;
next_free_action->a_action = action;
next_free_action->a_arg_vp = arg;
next_free_action->a_res_vp = NULL;
next_free_action->a_next_p = NULL;
*action_list = next_free_action;
}
#define add(list, action) append_action(&(list), (action), NULL)
void erase_act_list(struct action **action_list)
{
struct action **last_action_pp = action_list;
while (*last_action_pp)
last_action_pp = &(*last_action_pp)->a_next_p;
*last_action_pp = free_action;
free_action = *action_list;
*action_list = NULL;
}
void perform_actions(struct action *action_list)
{
while (action_list) {
action_list->a_res_vp = action_list->a_action(action_list->a_arg_vp);
action_list = action_list->a_next_p;
}
}
#define DECL_PRINT_ACTION(mess) \
void *print_##mess(void *arg) \
{ \
printf(#mess); \
return NULL; \
}
#define add_prints_2(list, m1, m2) \
add((list), print_##m1); \
add((list), print_##m2)
#define add_prints_5(list, m1, m2, m3, m4, m5) \
add_prints_2((list), m1, m2); \
add_prints_2((list), m3, m4); \
add((list), print_##m5)
DECL_PRINT_ACTION(hello)
DECL_PRINT_ACTION(world)
DECL_PRINT_ACTION(to)
DECL_PRINT_ACTION(be)
DECL_PRINT_ACTION(or)
DECL_PRINT_ACTION(not)
DECL_PRINT_ACTION(all)
DECL_PRINT_ACTION(right)
void *print_space(void *arg)
{
printf(" ");
return arg;
}
void *print_line(void *arg)
{
printf("\n");
return arg;
}
void test(void)
{
struct action *hw_acts;
struct action *hamlet_acts;
struct action *all_right;
init_act_list(&hw_acts);
init_act_list(&hamlet_acts);
init_act_list(&all_right);
add(hw_acts, print_hello);
add_prints_5(hamlet_acts, to, space, be, space, or);
add(hw_acts, print_space);
add(hamlet_acts, print_space);
add(hw_acts, print_world);
add(hamlet_acts, print_not);
add(hw_acts, print_line);
add(hamlet_acts, print_space);
add_prints_2(hamlet_acts, to, space);
add_prints_2(hamlet_acts, be, line);
perform_actions(hw_acts);
perform_actions(hamlet_acts);
erase_act_list(&hamlet_acts);
perform_actions(hw_acts);
perform_actions(hamlet_acts);
add_prints_2(all_right, all, space);
erase_act_list(&hamlet_acts);
add_prints_2(all_right, right, line);
perform_actions(all_right);
}
int main(void)
{
init_actions();
test();
return 0;
}
PROG_NAME = chain_of_actions
${PROG_NAME}: ${PROG_NAME}.c
cc -g -O2 -Wall -pedantic $^ -o $@
@ramntry
Copy link
Author

ramntry commented Mar 17, 2013

Начитался я тут что-то исходных кодов MINIX 3 и захотелось мне вбросить в мир кусок кода на няшной сишке как иллюстрацию некоторого подмножества традиций наших дедов. Что получилось - смотрите выше.
Можно пронаблюдать:

  1. Изобилие макросов, определяемых и используемых вперемежку с остальным кодом. Часто с какими-то весьма странными именами: иногда просто неудачными, иногда кричащими "Я_МАКРОС", иногда тщательно маскирующимися под нормальные_функции. Использование макросов внутри кода макросов, а также #музыкальных ##расширений. Нелюбовь к директивам typedef и константам - макросы, безусловно, лучше.
  2. Использование сокращенных имён структур в качестве префиксов имён всех полей этих структур. Какая-то странная плавающая венгерская нотация - то она есть, то её нет. Страсть к сокращенным имёнам и аббревиатурам, которые, впрочем, тесно соседствуют в коде с полными именами.
  3. Активное использование указателей на функции и указателей на void (особенный трепет вызывает возможность определить в программе указатель (а лучше указатель на указатель) на функцию, которая принимает указатель на void и возвращает указатель на void - мммм...), любовь к связным спискам. Даже массивы меркнут перед великолепием списков - уж коли понадобился массив, то обращаться к его элементам мы будем исключительно через указатели. Разумно. Вдруг потом заменим массив списком? Индексы потеряют смысл, а указатели - нет. И вообще - арифметика указателей - наше всё.
  4. Обилие глобальных переменных.
  5. Избегание malloc'ов. Любимое развлечение - написать собственный менеджер памяти. Ну хотя бы мааааааленький.
  6. Постоянную ходьбу по лезвию ножа: существование ветви потока управления такой, что в ней некоторая область памяти будет проинициализирована чем-нибудь разумным (например, нулём) дважды - смерти подобно. Размеры буферов, пулов и прочего подбираются с хирургической точностью.
  7. Экономию места в листинге. В частности, если тело условного оператора или оператора цикла состоит из одного оператора, то в блок его, конечно же, заключать не стоит. Очень трудно не поддаться искушению вообще весь объемлющий оператор в одну строчку записать. Впрочем, пустые строки можно себе иногда позволить. Даже там, где они совершенно не нужны. Just for fun (c).

А что ещё заметили вы? (указать "программирование без пробелов" и "программирование под K&R-компиляторы" я как-то постеснялся, sorry)

UPD. Спецификаторы static перед глобальными переменными добавлены по замечанию пользователя habrahabr.ru

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment