LINUX.ORG.RU

Реализация функций, делающих одно действие с разными полями структуры

 ,


1

5

Добрый день.
Есть такая структура:

struct tmatrix_entry {
	double price;
	double amt;
};

struct tmatrix {
	struct tmatrix_entry **entries;
	double *stocks;
	double *needs;
	int rows;
	int cols;
};
И есть функции, обеспечивающие доступ к некоторым её членам:
void tmatrix_set_prices (struct tmatrix *tm, double *prices[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j)
			tm->entries[i][j].price = (prices) ? prices[i][j] : 0;
}

void tmatrix_set_amts (struct tmatrix *tm, double *amts[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j)
			tm->entries[i][j].amt = (amts) ? amts[i][j] : 0;

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

enum field {
	PRICE, AMT
};

static void set_entries_values (struct tmatrix *tm, enum field field, double *values[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j) {
			if (field == PRICE)
				tm->entries[i][j].price = (values) ? values[i][j] : 0;
			else if (field == AMT)
				tm->entries[i][j].amt = (values) ? values[i][j] : 0;
		}
}

void tmatrix_set_prices (struct tmatrix *tm, double *prices[]) {
	set_entries_values(tm, PRICE, prices);
}

void tmatrix_set_amts (struct tmatrix *tm, double *amts[]) {
	set_entries_values(tm, AMT, amts);
}
Или не париться и выносить в хэдер «универсальную» функцию? Как вообще это делают белые люди?



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

Вопрос: как избежать дублирования повторяющегося кода?

tmatrix_set

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

Макросами (не проверял, может где-то опечатался):

#define TMATRIX_SET(TM, FIELD, ARRAY)\
do {\
	for (int i = 0; i < TM->rows; ++i)\
		for (int j = 0; j < TM->cols; ++j)\
			TM->entries[i][j].FIELD = (ARRAY) ? ARRAY[i][j] : 0;\
} while(0)

Использование:

TMATRIX_SET(tm, price, prices);
TMATRIX_SET(tm, amt, amts);
anonymous
()
Ответ на: комментарий от deep-purple

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

А вот для микроконтроллеров — уже смотря что тебе надо. Нужна производительность — фигачь макросы; нужно уложиться в маленький объем флешки — пиши функции.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от deep-purple

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

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

Спасибо, добрый аноним. Фишка с do…while(0) прикольная. Век живи — век учись. Ещё б с offsetof() пример кто подкинул.

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

Ещё б с offsetof() пример кто подкинул.

man открой! Там пример есть. По сути offsetof просто вычисляет разность указателей.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от anonymous

А что насчёт такого варианта: этот макрос определяем в tmatrix.c, там же в функциях-обёртках пишем:

void tmatrix_set_prices (struct tmatrix *tm, double *prices[]) {
	TMATRIX_SET(tm, price, prices);
}

void tmatrix_set_amts (struct tmatrix *tm, double *amts[]) {
	TMATRIX_SET(tm, amt, amts);
}
И потом эти обёртки опять выставляем напоказ в хэдере. Нормально?

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

С offsetof (тоже не проверял, может быть каких-то скобочек не хватает):

void tmatrix_set (struct tmatrix *tm, size_t fld_off, double *data[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j)
			*(double *)((void *)&tm->entries[i][j] + fld_off) = (data) ? data[i][j] : 0;
}

Использование:

tmatrix_set(tm, offsetof(struct tmatrix_entry, price), prices);
tmatrix_set(tm, offsetof(struct tmatrix_entry, amt), amts);

Вариант с offsetof() хуже тем что поля предполагаются одного типа (double в твоем случае)

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

Ну сделать-то можно как угодно, просто хочется ведь, чтоб по понятиям, такскть…

PamidoR
() автор топика

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

enum {
  TMATRIX_ENTRY_PRICE,
  TMATRIX_ENTRY_AMOUNT,
  TMATRIX_ENTRIES
}
typedef double tmatrix_entry[TMATRIX_ENTRIES];

struct tmatrix {
	struct tmatrix_entry **entries;
	double *stocks;
	double *needs;
	int rows;
	int cols;
};
int tmatrix_set_entries(struct tmatrix *m,int entry,double * const data[]) {
  if (entry<0 || entry>=TMATRIX_ENTRIES) return -1;
  // bla-bla-bla
  for(i=....)
    for(j=...)
       m[i][j][entry]=data[i][j];
  return 0;
}
#define tmatrix_set_prices(m,data) tmatrix_set_entries((m),TMATRIX_ENTRY_PRICE,(data))
#define tmatrix_set_amounts(m,data) ...

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

Тогда эти дефайны не будут видны юзеру библиотеки. А в хедере мне надо выставить tmatrix_set_prices() и tmatrix_set_amts(), скрыв при этом действительную реализацию.

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

вопрос-то в чём? какой дефайн в какой хедер засунуть, чтоб юзеру было максимально неудобно и самому коряво, что-ли?? :-)

#ifndef MY_H
#define MY_H 1
// public header for fucking user

// hide structure 
struct matrix_shmatrix;
typedef matrix_shmatrix *TheMatrix;

// only bugged public interface
TheMatrix create_matrix(int,int);
int matrix_set_amount_from_array(TheMatrix,double **);
#endif
// my.c follows
// private implementation
// never #include "my.h" - user must die

// real structure
enum SHMATRIX_ENTRY_IDS {
    ENTRY_PRICE,
    ENTRY_AMMOUNT,
    TOTAL_SHMATRIX_ENTRY_IDS
};
typedef double shmatrix_entry[TOTAL_SHMATRIX_ENTRY_IDS];
struct matrix_shmatrix {
   shmatrix_entry **data;
   ....
};
//// internal impl. should be static
static int matrix_set_entry_from_array(TheMatrix,enum SHMATRIX_ENTRY_IDS,double **);

//// inlines public interface to private static impl.
__attribute__((always_inline))
inline int matrix_set_amount_from_array(TheMatrix m,double **data) {
    return matrix_set_entry_from_array(m,ENTRY_AMOUNT,data);
}
__attribute__((always_inline))
inline int matrix_set_price_from_array(TheMatrix m,double **data) {
    return matrix_set_entry_from_array(m,ENTRY_PRICE,data);
}

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

Ну хз… спорить не буду, я гораздо менее опытен и меня этот код немношк пугает. Пока буду использовать свой вариант. Спасибо за ответ.

PamidoR
() автор топика

Если бы речь шла о C++, то я бы посоветовал указатели на член класса.

void tmatrix_set_values (tmatrix *tm, double tmatrix_entry::*field, double *values[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j)
			tm->entries[i][j].*field = (values) ? values[i][j] : 0;
}

tmatrix_set_values(&tm, &tmatrix_entry::price, values);
tmatrix_set_values(&tm, &tmatrix_entry::amt, values);
NeXTSTEP ★★
()

US∃ CØMMOИ ЛNСП

anonymous
()
Ответ на: комментарий от deep-purple

правила в с89 поменялись.

можно всегда было и есть но с с89 по другому.

qulinxao ★★☆
()
Ответ на: комментарий от MKuznetsov
// my.c follows
// private implementation
__attribute__((always_inline)) inline

Эти эксперты, эти эксперты. Атрибут - это контрольный? Ну чтоб логика происходящего упала и не встала.

matrix_set_price_from_array(TheMatrix m,double **data)

Вот зачем изменять своему призванию? Зачем? Призван мести улицу - мети. Зачем людей пугать и над собою издеваться? Сделай хоть что-то полезное для мира.

anonymous
()

Как вообще это делают белые люди?

Зачем использовать си, если не дано? Ведь чувствуется перебежчик, а зачем на си?

void tmatrix_set_prices (struct tmatrix *tm, double *prices[]) {
	for (int i = 0; i < tm->rows; ++i)
		for (int j = 0; j < tm->cols; ++j)
			tm->entries[i][j].price = (prices) ? prices[i][j] : 0;//это
}

Мне вот интересно, чем ты руководствовался когда писал «это»? Это такая черезжопу реализованная скрытая нелогичная логика?

Это просто моча в лицо. Как такую логику работы можно было вообще придумать. Хоть скобочки радуют.

Как вообще это делают белые люди?

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

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

Ты не дописал вторую часть ответа. А именно - как сделать правильно, не по перебежски. И у ТСа была там затравка если он не прав то показать как вообще сделать иначе.

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

Я откуда знаю что там ТС делает? Пусть опишет задачу - я покажу как я считаю правильным. Мы сравним.

И у ТСа была там затравка если он не прав то показать как вообще сделать иначе.

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

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

Зачем юзать си? Плюсов си ты не получаешь, но зато получаешь тотальную садомию в своей лапше.

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

Ну тогда подождем ТСа, пусь скажет чо и как. Мне тоже не нравится что он нахреначил у себя какие-то вложенные структы, и теперь «влагает» циклами шоп добраться до нужных полей.

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

name: Вася
age: 23
gender: male
parts: (тело, голова, рука, рука, нога, нога, писька)

Как это все хранить правильно и с удобным доступом?

deep-purple ★★★★★
()
Ответ на: комментарий от anonymous

Ну тута я

Задача: сделать некое подобие библиотеки для решения транспортных задач. То бишь предоставить тип tmatrix, и функции, которые эту матрицу решают и предоставляют интерфейс к её внутренностям. Всё.

PamidoR
() автор топика
Последнее исправление: PamidoR (всего исправлений: 1)
Ответ на: комментарий от deep-purple

Ну, предположим надо запилить хрень которая умеет некий список

С этим в детсад.

(добавить, удалить, изменить)

С этим тоже - таких понятий на этом уровне не существует.

каждый элемент списка мы должны показывать юзеру в виде:

Меня не интересует как и что я должен кому-то показать. Это задача примитивной скриптухи. И уж это точно я не буду учитывать это при запиле.

Как это все хранить правильно и с удобным доступом?

Что есть доступ опять же не описано. Что такое удобный доступ? Чего доступ? Можешь конкретней сформулировать задачу?

Как правильно хранить - зависит от задачи. Сформулируй внятное ТЗ - я запилю - посмотрим.

anonymous
()
Ответ на: Ну тута я от PamidoR

Задача: сделать некое подобие библиотеки для решения транспортных задач.

Это не задача, а мусор. Чего подобие, какой бидлиотеки? Для решения каких таких «транспортных задач»? Мне это ниочем не говорит.

Вот что мне дала твоя крайне полезная информация? Я узнал что твои задачи «транспортные», ну дак это мне ничего не сказала и мне насрать как там они у вас называются.

То, что ты ваяешь «библиотеку» - дак это же ваяют 99% тебе подобных ваятелей, в чем собственно был посыл? Это для меня не новость.

То бишь предоставить тип tmatrix

А нахрен мне сдался твой тип? Он нужен тебе, а не мне и не твоей задаче.

Я вообще не понимаю откуда берутся такие люди, которые не отличают реализацию от задачи. Причем таких 95%, если не 98.

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

Тебе надо отвечать «у меня такая-то задача(допустим тот же формат хранения). Есть такие данные. Надо хранить из них то-то. Надо иметь такой-то доступ к тому-то, а сякой-то доступ к сему-то.»

и функции, которые эту матрицу решают

Какую ещё, нахрен, матрицу? Как и чего они там решают? Очередной деревенский эмулятор табличек из екселя?

предоставляют интерфейс к её внутренностям

Что такое «интерфейс», какие у неё внутренности и зачем.

Попытайся внятно и конкретно сформулировать задачу не привязываясь к своим реализациям и попыткам к ваянию.

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

Ладно, формулирую.

Необходимо реализовать приложение (визуальная часть не важна) в котором пользователь может строить «блоки». У каждого блока есть поля: «a» и «b». К каждому блоку можно прикрепить любое кол-во потомков - таких же блоков.

Для поля «a»:

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

Для поля «b»:

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

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

Необходимо реализовать приложение

Это не ко мне. Я не занимаюсь хернёй заниматься которой удел нулёвой обезьяны.

(визуальная часть не важна)

Меня абсолютно не интересует твоя «визуальная» часть в любом виде.

в котором пользователь может строить «блоки».

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

У каждого блока есть поля: «a» и «b». К каждому блоку можно прикрепить любое кол-во потомков - таких же блоков.

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

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

Ну, в чем смысл? О5 абстрактный балаболизм.Тебя просили описать конкретную задачу, но о5 же, кроме абстрактной муры я ничего не услышал.

Зачем ты пытаешься абстрактное говно выдать за какую-то задачу?

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

Что такое «ближайшие» потомки? Это какие?

Мне лень заниматься этой бесполезной хернёй. В чем заключается сложность, полезность сего действа?

typedef struct {
  int32_t a, b;
} data_t;

typedef struct block {
  data_t val;
  uint32_t last_level;
  struct block * level[0];
} block_t;
//юзать так:
  block_t * block = malloc(100500);
  block->val = (data_t){1, 2};
  block->level[0] = malloc(100500);
  block->level[0]->val = (data_t){2, 3};
  block->level[0]->level[0] = malloc(100500);
  block->level[0]->level[0]->val = (data_t){3, 4};

Надеюсь как это обойти ясно?

И да, ты же придумаешь хоть одно назначение этой бесполезной муры, для которого я не придумаю намного более лучшую и удобную реализацию?

И ты же мне найдёшь юзкейс в котором надо хотябы 2-3вложения, ибо я уж не говорю о «сколько угодно».

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

anonymous
()
Ответ на: комментарий от deep-purple

Я тебе завуалировал то как работает DOM/CSS двигло в браузере

И? Что это меняет? Что следует из твоего ответа?

Твоя херня вдруг стала не абстрактной? Или чё?

Тем более «DOM/CSS двигло» в броузере априори бездарное придуманное говно и является такой же абстрактной хернёй.

Устроит такой НЕабстракт?

Что?

anonymous
()
Ответ на: комментарий от deep-purple

Собственно ответом я удовлетворен

Чем конкретно.

Растолковал.

Собственно это ответ ниочём.

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

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

Что следует из твоего ответа?

Ты предвзято относишься ко всем вопросам, вот что.

«DOM/CSS двигло» в броузере априори бездарное придуманное говно

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

deep-purple ★★★★★
()
Ответ на: комментарий от x4DA

копипаста норм

Ага, а когда копипасты наберется >2, то при правке кода очень весело вычислять что и где необходимо поправить.

nagibator
()
Ответ на: комментарий от deep-purple

Ты предвзято относишься ко всем вопросам, вот что.

Если он говно - я отношусь к него как к говну. Если ты со мною не согласен - дак объясни мне, почему, собственно, твой ответ не говно.

Да и ты просто проигнорил все мои вопросы.

Так сделай лучше раз могёшь.

Сделать лучше конкретно что?

Или хотябы поучаствую в существующих реализациях.

А, дак ты про реализации. В этом вся ваша проблема - мне не нужно реализовывать говно, чтобы сделать лучше. Мне не надо хреначить матрицы ТС"а - он их запилил туда по причине того, что не подумал.

Такая же штука и с твоим браузёром. Твой mod/css там по такой же причине - кто-то когда-то не подумал, а теперь никто не хочет отказываться от говна.

Собственно даже дело не в том, чтобы от него отказаться - вы даже не понимаете, что это можно сделать. Вы не отличаете задачу/реализацию/решение. Для тебя сделать лучше - это реализовать лучше, но говне не реализуется лучше by design.

anonymous
()
Ответ на: комментарий от deep-purple

Твои описание избыточно. Тут нахрен не нужна никакая вложенность. У тебя какая-то херня и зависимые от неё херни. Ты перечисляешь зависимые херни в свойствах херни.

typedef void(*fptr_t)(void);

typedef struct {
  uint32_t val;
  fptr_t use[0];
} val_t;

void base(uint32_t * v, uint32_t x) {
  fprintf(stderr, "%u\n", *v * x);
}

#define bind2(fun, arg, arg2) ((typeof(fun(arg, arg2))(*)(void))({\
 typeof(fun(arg, arg2)) __fun(void) {\
   return fun(arg, arg2);\
 }\
 __fun;\
}))

void update_val(val_t * val, uint32_t v) {
  val->val = v;
  typeof(*val->use) * use = val->use;
  while(*use) (*use++)();
}

#define write_initlist(to, ...) ({\
  memcpy(to, &(typeof(__VA_ARGS__)[]){__VA_ARGS__}, sizeof((typeof(__VA_ARGS__)[]){__VA_ARGS__}));\
})

int main(void) {
  val_t * val = calloc(1, 100500);
  write_initlist(val->use, bind2(base, &val->val, 2), bind2(base, &val->val, 3), bind2(base, &val->val, 4));
  update_val(val, 123);
}

Это более илитно. И уже заточено под гуйню. Но один хрен это убого в любом виде.

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

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

Я не все понимаю синтаксически что тут происходит. В частности объявление макросов - почему(зачем) обернуты в ({ }). А описание bind2 так вообще темный лес (чота там кастуется). Но это не суть, все гуглится, главное принцип понятен.

У меня есь вопросы, и второй намного важнее: 1) разве эстетически не важно сначала задефайнить макросы, затем структы, и только потом ф-ции? (или в каком порядке надо чтоб красиво/правильно было?) 2) выбирая, что сделать макросом, а что ф-цией - ты чем-то руководствовался или писал как в голову пришло?

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

Хрена ты намудрил.

Ну вроде там в вебе щас ленивость продвигается, не? «Мудрёж» тут только с самим запилом, а так дефолтная байда.

Я не все понимаю синтаксически что тут происходит.

Ну это не чистые си.

В частности объявление макросов - почему(зачем) обернуты в ({ }).

Это не макросы - это типа «функции» из гнуси. Она так же возвращают аргумент, они так же имеют свою область видимости.

write_initlist в неё обвёрнут, чтобы иметь такую же семантику, как и мемкопи - он возвращает возврат мемкопи.

Т.е. можно писать void * p = write_initlist(...);

А описание bind2 так вообще темный лес (чота там кастуется).

#define bind2(fun, arg, arg2) ((typeof(fun(arg, arg2))(*)(void))({\
 typeof(fun(arg, arg2)) __fun(void) {\
   return fun(arg, arg2);\
 }\
 __fun;\
}))


//((typeof(fun(arg, arg2))(*)(void)) - этот каст - кастыль, чтобы не ломался синтаксис.

//fun(bind(a, b, c)) это раскроется в
fun(({...})) // это конпелятор не распарсит, поэтому каст-кастыль спасат.

Она создаёт новую функцию в которую захардкоривает вызов базовой функции и 2 её аргумента.

1) разве эстетически не важно сначала задефайнить макросы, затем структы, и только потом ф-ции?

Они стоят в том порядке, в котором я их написал. Потом, когда они написаны - я их уже сортирую и делаю карасиво/понятно.

Я считаю, что пацаны, которые хреначат «сначала маросы, потом структуры и только потом функции» - тотальные и бездарные дауны.

Во-первых. Структуры - это основа. На них уже строится логика, поэтому структура всегда пишется первой и должна стоять первой.

Во-вторых. За структурой следует логика, которая относится только к этом структуре. Далее уже логика другой, а уже потом общая логика, которая строится на отдельной логике.

Это всё илитно, сразу и понятно рассовывается по хедерам.

Никогда не понимал этого даунистического желания сваливать всё в несвязные кучи.

выбирая, что сделать макросом, а что ф-цией - ты чем-то руководствовался или писал как в голову пришло?

Я использую макросы тогда, когда мне нехватает возможностей функций.

Макросы - это автоматическая паста. Мне лень было писать {a, b, c}, а потом писать это ещё раз, чтобы сделать сайзоф - я написал макрос, который сделал это за меня. Собственно это и есть назначение макросов, а назначение функций немного иное.

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

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