LINUX.ORG.RU

с, структура/данные/наполнение, как оптимизировать?!

 , , ,


0

4

день добрый, товарищи колдуны! :о)

краткое строение проекта:

- struct.x      - описание структуры, массив/список данных/структур, функции работы со структурой/списком.
- struct_cust.x - кастомные данные, создание экземпляров структуры, добавление в "список"

некоторые неудобства:

- наполнение данных/добавление в "список" происходит в реализации/struct_cust.с
- установка счетчика списка в хедере/struct_cust.h

по другому не получилось «реализовать»,хотелось бы все логично/в одном месте:

- создание данных/добавление в список
- определение/установка счетчика

какие есть мнение/идеи/хаки-каки итд?!

- linux, gcc, c-pure

спасиб
...

main.c

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "main.h"
#include "struct.h"

int main (void)
{
printf("### struct ###\n");
struct_list();
return 0;
}

struct.h

struct data_struct 
{
uint8_t num;
void  (*func)(uint8_t id);
};

void struct_list(void);

struct.c

#include "struct.h"
#include "struct_cust.h"

struct data_struct * lst[NUM];

void struct_list()
{
printf("struct_list()\n");

for(uint8_t i=0; i<NUM; i++)
  {
  printf("lst[%u].num = %u; ",i, lst[i]->num);
  if(lst[i]->func != NULL)  { lst[i]->func(i); }
  printf("\n");
  }
}

struct_cust.h

#define NUM 3
void struct_cust_func(uint8_t id);

struct_cust.c

#include "struct.h"
#include "struct_cust.h"

struct data_struct data1 = { .num = 1, .func = struct_cust_func };
struct data_struct data2 = { .num = 2, };// .func = struct_cust_func };
struct data_struct data3 = { .num = 3, .func = struct_cust_func };

extern struct data_struct * lst[NUM];
       struct data_struct * lst[NUM] = { &data1, &data2, &data3 };

void struct_cust_func(uint8_t id)
{
printf("struct_cust_func(%u)", id);
}

makefile

all: main.o struct.o struct_cust.o
	gcc -o main main.o struct.o struct_cust.o

main.o: main.c
	gcc -c main.c

struct.o: struct.c
	gcc -c struct.c

struct_cust.o: struct_cust.c
	gcc -c struct_cust.c

clean:
	rm -f *.o main

main out

### struct ###
struct_list()
lst[0].num = 1; struct_cust_func(0)
lst[1].num = 2;
lst[2].num = 3; struct_cust_func(2)

### UPDATE ###
торопился, думал опишу коротко и понятно, видимо, не получилось.

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

общее описание (плюс минус, для понимания)

есть главный модуль (main.c) - он ... он просто главный, использует «данные» и «функции», оперирующие с этими данными.
struct.x - модуль/бибилотека, описывает структуру и содержит в реализации функции, работающие с «данными» структурами.
strucr_cust.x - модуль с пользовательскими данными, созданными на базе «структур», описанных в struct.h

в этом модуле мы создаем данные (3 штуки структуры, добавляем их в список структур lst[NUM], с которым работает библиотка struct.c)
так-же тут мы определяем пользовательские функции, но это уже другой уровень, не важно... главное то, что модуль stuct_cust.x - содержит наши данные и будет в будущем модернизироваться (создаваться новые еденицы структур, тут-же добавляться в массив/список lst[NUM])

так вот, при создании/добавлении структур - есть некоторое разделение
- strucr_cust.c создание экземпляров структур
- strucr_cust.h - определение глобальной константы NUM - число структур в списке

хотелось-бы все делать в одном месте (создавать экземпляры структуры, изменять/настраивать счетчик NUM, добавлять структуры в список lst[NUM])

собственно, не очень и сложно : добавил структуры, зашел в хедер, изменил макрос NUM - и ву-а-ля, можно далее в ус не дуть! :о)

в 2х словах это как-то так. если что - спрашивайте. :о) спасибо

★★★★★

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

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

у тебя main.c просто принтует заголовок и дампит какой-то неведомый массив из непойми чего, и чтобы понять откуда он вообще взялся, надо ковыряться в исходниках.

то есть имеем программу под названием - дамп массива, сокрытого тайной неизвестности. кому нужна такая программа - непонятно.

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 3)

Не понял в чём у тебя проблема. Заметил только, что форматирование блоков кода { ... } ужасное.

Если кода столько как в примерах - то весь его надо сгрузить в один единственный файл размером в несколько кбайт максимум.

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

Странный код

ничего странного, это выпотрошенный/минимальный шаблон с рабочего проекта (воспринимайте так)

Что мешает?
по другому не получилось «реализовать»

-->

все логично/в одном месте:
- создание данных/добавление в список
- определение/установка счетчика

-->
переносим макрос NUM в реализацию (в одно место с определением кастома), получаем ошибку и далее по накатаной...

struct.c:11:26: error: ‘NUM’ undeclared here (not in a function)
 struct data_struct * lst[NUM];
                          ^
если есть идеи/решение - велкам! :о)

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

Заметил только, что форматирование блоков кода { ... } ужасное.

как мы тут заметили, у вас вечные проблемы с форматированием! :o)

Какой ужасно форматированный (да вобщем-то и вообще ужасный) код автора кода и какой орфографически ужасный вопрос от автора темы

не берите на себя столько, а то не унесем не вы и не мы!
давайте, лучше по коду/топику.
если что не понятно спрашивайте, это не страшно! :о)
p.s. еслиф что - там везде смайлики :о)

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

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

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

alysnix ★★★
()

А оно у вас точно собирается, а то, похоже, что в единице трансляции struct_cust.c остаётся неопределённым uint8_t. Мне кажется, стоит подключать stdint.h явно. Ещё мне кажется, стоит объявлять data1, data2, …, lst константными, если они у вас неизменяемы.

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

вы бы лучше разобрались что там происходит! а то сразу «все плохо»... шеф... :о)

взаимное включение
- необходимо «условием топика», иначе-бы и вопросов не было (нужно только для видимости макроса константы, более низачем)
- защищено препроцессором

архив с прототипом

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

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

for(uint8_t i=0; i<NUM; i++)

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

да все нормально по-моему. Если начать дальше упарываться по проектированию дойдет до абстрактной фабрики этих struct_cust.

И я не очень понял насчет NUM как макроса. если появится еще один другой struc_cust они будут перезаписывать друг друга при инклудах? А если нет зачем тогда struc_cust вместо одного struct?

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

:o) - да да... именно :о) аж самому смешно! собственно, спасибо за то, что поняли меня, такого непонятного! жму лапу!

п.с. обновил топик, добавил более дотошное описание.

п.с.2 увидел исправление, сейчас попробую подумать! :о)

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

дело не в «защите препроцессором», а в том, что взаимный импорт говорит о том, что файл искусственно разорван на две части.

неохота вникать в ваши проблемы, с чего бы оно так вам надо,… но даже если оно так надо - просто имейте два хидера, но один общий файл реализации.

в си(и плюсах) такое вполне нормально. зачем вам два си файла-то со структурами этими?

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

короче там функция должна быть

struct_list( data_struct* flist, uint flen)

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


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

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

не очень понял насчет NUM как макроса.
если появится еще один другой struc_cust они будут перезаписывать друг друга при инклудах?

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

А если нет зачем тогда struc_cust вместо одного struct?

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

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

неохота вникать в ваши проблемы

таки уже и не надо, зачем оно вам?! смиритесь! :о) думаю мы разберемся сами, с парнями, они у нас тут отзывчивые!

и вам не хворать, и всего хорошего! :о)

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

ну такое (или около того) - сейчас и работает (проект-то пишится)! :о)

просто напросто я решил все сделать удобно (блин... сам себе вот такой вот цирк :о)

еще раз спасибо, глядите в суть, прям мысли читаете! :О)

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

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

Очень здоровая часть функций main() в разных проектах – инициализация ресурсов и вызов ивент-лупа.

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

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

карочи пишите struct_list так

struct_list( data_struct* flist, uint flen)

и не морочьте головы окружающим.

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

да что-же такое?! что вы советуете, а?! ведь это могут и дети прочитать?!

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

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

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

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

сообщением выше я добавил ссылку на архив с прототипом

Ага, там уже неразбериха с хидерами поправлена, ок.

Из того, что ещё сильно бросается в глаза:

Во-первых перенести определение из struct.c:struct data_struct * lst[NUM] в extern struct data_struct * lst[NUM];:struct_cust.h.

А во-вторых заменить #define NUM 3 на #define NUM (sizeof(lst) / sizeof(lst[0]))

Ну и ключевое слово const для констант, как пожелание.

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

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

зы
перенос эктерна в кастом-хедер - не обязателен

 
extern struct data_struct * lst[NUM];

я сделал определение экстерна в самой реализации, сделав определение «локальным» только в реализации, а не в хедере, мало-ли кто/кому еще потребуется хедер подключить в будущем (опять-таки, поправь, если я не прав?!)

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

ну вот видите, начали, правда, не совсем конструктивно, но все-же делаете усилия над собой! продолжайте и мы с вами подружимся! :о)

p.s.

вы в си третий день

да меня вообще там нет, я тут, в экране монитора, с клавиатурой! как сами там будете - свистите, пообщаемся! :о)

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

в целях оптимизации, предлагаю:

1. сократить названия файлов и сущностей, это сэкономит место на диске, пространство визуального редактора и ускорит компиляцию. struct.h резко переименовываем st.h и struct data_struct в struct data_st.

вроде-бы мелочь но оптимизация должна быть оптимальной. Заодно нет конфликта имён и понятий

2. писателю make-файла дать по шапке и уволить. Это экономит бюджет проекта и позволяет сократить makefile вдвое и сделать его управляемым

3. автора идеи и именования main.h отправить за makefile писателем

4. всё что в struct_cust.h удалить нах. Автора понятно куда

минус 3 ненужности в проекте ;-)

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

сократить...

да-да, согласен! особенно сократить общение с такими комментаторами!

и вам не хворать и не падать в гололед! :о)

p.s. спасибо посмеялся :о)

sunjob ★★★★★
() автор топика
Последнее исправление: sunjob (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov
  1. сократить названия файлов и сущностей, это сэкономит место на диске

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

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

я сделал определение экстерна в самой реализации, сделав определение «локальным» только в реализации, а не в хедере, мало-ли кто/кому еще потребуется хедер подключить в будущем (опять-таки, поправь, если я не прав?!)

Не уверен, что понял это предложение. На мой взгляд, такое определение стоит иметь в заголовочном файле. Если «кому-то» ещё понадобится определение lst, то «он» этот файл подключит.

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

не, не подключит :о) потому как список вообщем-то это приватные данные библиотеки (пока, во всяком случае, поэтому и доступ только от туда, откуда надо)

возможно, с развитием библиотеки понадобиться, но пока не вижу :о)

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

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

А уж глобальные переменные, внутреннее содержание доступное всем и каждому вообще сказка. Для взрослых.

какие есть мнение/идеи/хаки-каки итд?!

Переписать все на классах С++ с нормальным неймингом, вместо сырых указателей на объекты использовать умные указатели, а вместо сырых массивов использовать вектор. И так через месяц и через год можно будет вспомнить, не перенапрягаясь, для чего это писалось, а в случае ошибок оно хотя бы будет падать, а не показывать среднюю температуру Марса.

Ygor ★★★★★
()

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

то есть резервировать массив на элемент больше, и в последний элемент писать null.

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

то есть ваш NUM вовсе не обязателен.

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

и в последний элемент писать null

на сколько я понял:
в нулевой элемент [0] последней (занулЁнной) структуры.

ну... это-же, конечно, полная глуппость!
если уж так сильно волнует «счетчик», то в таком случае создается еще одна структура (со списком и счетчиком)... и ни каких проблем. я не хочу плодить сущности, поэтому был такой изврат.

доп. для отладки/процесса написания - удобнее иметь константу-счетчик (кол-ва элементов), кот. можно менять в зов-ти от отладки (к слову)

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

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

struct data_struct * lst[NUM] = { &data1, &data2, &data3 };

вот и добавь еще элемент в хвост, и запиши туда нул, то есть адрес равный НУЛЮ. и ходи по массиву пока не встретишь этот нул, в своих циклах…

вот так напиши

struct data_struct * lst[] = { &data1, &data2, &data3, NULL };

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

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

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

ничего вы не поняли.

на сколько я понял:
в нулевой элемент [0] последней (занулЁнной) структуры.

«насколько» пишется слитно.

никакой там «зануленной структуры» нет, и «ее нулевого элемента» тоже.

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

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

учите сначала что такое указатель(обозначается звездочкой после типа), взятие адреса переменной - аперсанд перед ее именем, и как записывается массив.

и еще - в си, как жаваскрипте или пытоне не пишут.

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

заканчивайте ваши рОзмЫсли! я же вам написал, что понял все сразу...(с первого раза не доходит?!)

если хотите, считайте как вам угодно (и ЭТУ тему закончили), далее только по топику (кроме глупостей как использовать «пустые» данные у вас есть еще идеи?)

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

если хотите, считайте как вам угодно (и ЭТУ тему закончили), далее только по топику (кроме глупостей как использовать «пустые» данные у вас есть еще идеи?)

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

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

ваша возня с количеством совершенно в вашем случае не нужна. и при отладке (вы во какие слова прочитали уже!) она тоже не нужна.

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

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

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

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

До тех пор, пока кто-то умный не запишет null в середину массива каким-нибудь деструктором, куда передается элемент массива по ссылке.

еще один сверхразум. массив с нулом в конце, это по сути вариант списка у которого последний линк есть нулл.

и с вашими мыслищами так и обычные списки не нужны - а что если кто-то в средине список разорвет, и поставит нулл, в поле next. и получит утечку - ай-яй-яй.

это называется - дурное дело нехитрое.

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

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

Упадет - это как раз хорошо. Много лучше чем будет течь, но не упадет.

Лично мое мнение, решение с нуллом в конце зайдет если нет операций типа добавления/удаления/замены и нет глубокой вложенности разыменований и прочего. Если список (а по факту массив) статический как у опа или список путешествует через десяток различных файлов - лучше задать длину константой или вообще завести структуру с полями длина и список.

Но если что я не настоящий сишник.

shimshimshim
()