Timonkaipumpa Δημοσ. 19 Νοεμβρίου 2011 Δημοσ. 19 Νοεμβρίου 2011 Μακαρόνι ξε-μακαρόνι.. το sys/sys/queue.h, από το FreeBSD, είναι με macros migf1 Στο link που σου παρέθεσα, εάν κάνεις λίιιιγο scroll έχει υλοποίηση single linked και double linked lists με "templates" σε C. Έχει σχόλια μέσα ο κώδικας και μπορείς να καταλάβεις τι γίνεται. Κάπου υπάρχει και το documentation για την χρήση των functions αλλά δεν θυμάμαι atm.
bokarinho Δημοσ. 20 Νοεμβρίου 2011 Δημοσ. 20 Νοεμβρίου 2011 Ας συμβάλλω και εγώ λίγο στην απορία σου με την δημιουργία λίστας με macro, αυτό που σου δίνω δημιουργείς μία λίστα πχ από floats. > typedef int list_pos_t; #define LP_START 0 #define LP_END 1 #define LIST(t) t##_list #define LNODE(t) t##_lnode // Declares types and function prototypes relevant to a list. #define DECLARE_LIST(t) \ typedef struct LNODE(t) {\ struct LNODE(t) *prev;\ struct LNODE(t) *next;\ t value;\ } LNODE(t);\ \ typedef struct LIST(t) {\ LNODE(t) *first;\ LNODE(t) *last;\ int count;\ } LIST(t);\ \ void t##_list_init(LIST(t) *l);\ LIST(t)* t##_list_new();\ void t##_list_add(LIST(t) *l, LNODE(t) *n, list_pos_t position);\ LNODE(t) *t##_list_remove(LIST(t) *l, list_pos_t position);\ typedef int (*t##_comparer)(t*, t*);\ LNODE(t)* t##_list_find(LIST(t) *l, t *item, t##_comparer cmp);\ LNODE(t)* t##_list_getNode(LIST(t) *l, t* pValue);\ void t##_list_removeNode(LIST(t) *l, LNODE(t) *n);\ LNODE(t) * t##_lnode_new(); // Defines the types and functions of a list. #define DEFINE_LIST(t) \ void t##_list_init(LIST(t) *l) {\ assert(l);\ l->count = 0;\ l->first = l->last = NULL;\ }\ \ LIST(t)* t##_list_new() {\ return (LIST(t)*)Malloc(sizeof(LIST(t)*));\ }\ \ *Δεν έχω προσθέσει όλο τον κώδικα μου, απλά καταλαβαίνεις πως συνεχίζει.
migf1 Δημοσ. 20 Νοεμβρίου 2011 Μέλος Δημοσ. 20 Νοεμβρίου 2011 Παιδιά σας ευχαριστώ πολύ για το ενδιαφέρον και την συμβολή σας! Ειλικρινά θα ήθελα να αποφύγω λύσεις με macros. Άλλωστε υπάρχει ήδη τέτοια library που είναι και πλήρης και δοκιμασμένη και ασφαλής (όσο ασφαλή μπορεί να είναι τα macros)... η SGLIB ( Reference, Download ). Αντίστοιχο του queue.h που πόσταρε ο φίλος Timonkaimpupa. @παπι: ο στανταρ τρόπος να γεμίζεις non-generic στοίβες είναι με values (τα constants είναι υποσύνολα των values). Π.χ. σε μια ομοιογενή στοίβα από int, το value των int περνάμε στην push και όχι τη διεύθυνσή τους... > for (i=0; i<10; i++) { stack_push( &stack, i); // και όχι: stack_push( &stack, &i); Εφόσον λοιπόν θέλουν υποστήριξη ΚΑΙ για primitive data-types, θεωρώ αυτονόητο ότι θέλουν να τα περνάνε με τα values τους, όπως είθισται. Άλλωστε αν περνιούνται οι διευθύνσεις τους δεν υπάρχει ουσιαστικός λόγος να διαχωριστούν από τα custom data (θα μπορούσα να κάνω τα πάντα treat ως void * και να τελειώνει η ιστορία, αυτό όμως είναι trivial, δεν χρειάζονται εμένα να τους το κάνω ) > typedef struct StackNode { void *data; void (*print_data)(void *data); struct StackNode *down; } StackNode; Bool stack_push( StackNode **stack, void *data, void (*print_data)(void *data) ); void stack_print_node( StackNode *node ) { node->print_data( node->data ); return; } Το θέμα είναι πως έχω αρχίσει και ζορίζομαι με την τιμή (βασικά τον τύπο) επιστροφής των generic stack_pop() και stack_peek() και μάλλον πρέπει να καταφύγω είτε σε εξειδικευμένες συναρτήσεις, είτε σε πέρασμα έξτρα παραμέτρου ΥΓ. Σιγά μην τους φτιάξω code-generator ρε συ, και αυτό που τους φτιάχνω free πολύ είναι!
bokarinho Δημοσ. 20 Νοεμβρίου 2011 Δημοσ. 20 Νοεμβρίου 2011 Παιδιά σας ευχαριστώ πολύ για το ενδιαφέρον και την συμβολή σας! Ειλικρινά θα ήθελα να αποφύγω λύσεις με macros. Άλλωστε υπάρχει ήδη τέτοια library που είναι και πλήρης και δοκιμασμένη και ασφαλής (όσο ασφαλή μπορεί να είναι τα macros)... η SGLIB ( Reference, Download ). Αντίστοιχο του queue.h που πόσταρε ο φίλος Timonkaimpupa. @παπι: ο στανταρ τρόπος να γεμίζεις non-generic στοίβες είναι με values (τα constants είναι υποσύνολα των values). Π.χ. σε μια ομοιογενή στοίβα από int, το value των int περνάμε στην push και όχι τη διεύθυνσή τους... > for (i=0; i<10; i++) { stack_push( &stack, i); // και όχι: stack_push( &stack, &i); Εφόσον λοιπόν θέλουν υποστήριξη ΚΑΙ για primitive data-types, θεωρώ αυτονόητο ότι θέλουν να τα περνάνε με τα values τους, όπως είθισται. Άλλωστε αν περνιούνται οι διευθύνσεις τους δεν υπάρχει ουσιαστικός λόγος να διαχωριστούν από τα custom data (θα μπορούσα να κάνω τα πάντα treat ως void * και να τελειώνει η ιστορία, αυτό όμως είναι trivial, δεν χρειάζονται εμένα να τους το κάνω ) > typedef struct StackNode { void *data; void (*print_data)(void *data); struct StackNode *down; } StackNode; Bool stack_push( StackNode **stack, void *data, void (*print_data)(void *data) ); void stack_print_node( StackNode *node ) { node->print_data( node->data ); return; } Το θέμα είναι πως έχω αρχίσει και ζορίζομαι με την τιμή (βασικά τον τύπο) επιστροφής των generic stack_pop() και stack_peek() και μάλλον πρέπει να καταφύγω είτε σε εξειδικευμένες συναρτήσεις, είτε σε πέρασμα έξτρα παραμέτρου ΥΓ. Σιγά μην τους φτιάξω code-generator ρε συ, και αυτό που τους φτιάχνω free πολύ είναι! Free? Δεν νομίζω να είσαι στα καλά σου... Συγγνώμη κιόλας...
παπι Δημοσ. 20 Νοεμβρίου 2011 Δημοσ. 20 Νοεμβρίου 2011 @παπι: ο στανταρ τρόπος να γεμίζεις non-generic στοίβες είναι με values (τα constants είναι υποσύνολα των values). Π.χ. σε μια ομοιογενή στοίβα από int, το value των int περνάμε στην push και όχι τη διεύθυνσή τους... Τοτε αρχησε να φτιαχνεις stack_bind_int,stack_bind_float, stack_bind_blob, etc... για να ακολουθησεις το "standar".
migf1 Δημοσ. 20 Νοεμβρίου 2011 Μέλος Δημοσ. 20 Νοεμβρίου 2011 Τοτε αρχησε να φτιαχνεις stack_bind_int,stack_bind_float, stack_bind_blob, etc... για να ακολουθησεις το "standar". Αυτό θέλω να αποφύγω, αλλά δεν βλέπω πως @bokarinho: χάρη σε φίλο κάνω (ελπίζω να το θυμηθεί σε λίγο καιρό που με βλέπω να επιστρέφω στην ενεργό δράση ) EDIT: Ευτυχώς που υπάρχει και το Copy & Paste, γιατί έχω ανοίξει θέμα και σε άλλο φόρουμ Έκανα κάποιες αλλαγές και το εξηγώ με περισσότερες λεπτομέρειες, με την ελπίδα πως θα σας είναι πιο εύκολο να προτείνετε κάποια λύση. --- Cut here ------------------------------------------------------------------------------------------------------------------ Για να το κάνω λίγο πιο σαφές, το πρόβλημα που αντιμετωπίζω είναι η διαχείριση primitive και custom data types μέσω generic functions, με τη δυσκολία να έγκειται στην "απαίτηση" τα primitive data types να μπορούν να διαχειριστούν ας το πούμε by value ενώ τα custom ας το πούμε by reference. Π.χ. αν θέλουμε να περάσουμε custom data ορισμένα ως: MyDType data, να γράφουμε: > stack_push( &stack, "%p", &data, sizeof( MyDType ) ); αλλά αν θέλουμε να περάσουμε κάποιο primitive data-type, π.χ. έναν int i, να γράφουμε... > stack_push( &stack, "%d", i ); // και όχι: stack_push( &stack, "%p", &i, sizeof(int) ); Αυτό λοιπόν το έχω υλοποιήσει και δουλεύει, βάση των παρακάτω ορισμών (τους έχω αλλάξει συγκριτικά με το αρχικό ποστ)... > typedef struct DataType { TypeId typid; union { long double valldouble; char valchar; int valint; double valdouble; } basic; void *pcustom; } DataType; typedef struct StackNode { DataType data; unsigned int count; struct StackNode *down; }StackNode; οπότε, το: data.basic αναφέρεται σε basic (primitive) data-types, π.χ... > node->data.basic.valchar; /* απλος χαρακτήρας */ ενώ το: data.pcustom αναφέρεται σε custom data, π.χ... > node->data.pcustom; /* δείκτης σε custom data */ Έχω φτιάξει και μια generic ρουτίνα εκτύπωσης που τυπώνει data of DataType > static int dump_stacknode_data( const DataType *pdata ); την οποία αφενός την χρησιμοποιώ σε μια ρουτίνα εκτύπωσης όλων των κόμβων της στοίβας... > void stack_dump( StackNode *stack ); και αφετέρου τυπώνει κανονικά τις τιμές των basic data-types, αλλά για τα custom data-types προς το παρόν τυπώνει μονάχα τη διεύθυνσή τους (τα strings τα κάνω treat ως special case των custom data, και τα τυπώνω κανονικά). Όταν προσθέσω υποστήριξη user-defined ρουτίνας εκτύπωσης για τα custom data στον κάθε κόμβο, θα την χρησιμοποιώ για κανονική εκτύπωση των values των custom data). Οπότε μέχρι στιγμής, με αυτόν τον κώδικα... > int main( void ) { struct MyData { int Int; float Float; } mydata; StackNode *stack = NULL; int i; for (i=0; i<3; i++) stack_push( &stack, "%d", i ); stack_push( &stack, "%s", "This is a string" ); stack_push( &stack, "%p", &mydata, sizeof(struct MyData) ); stack_dump( stack ); pressENTER(); stack_destroy( &stack ); exit( EXIT_SUCCESS ); } παίρνω αυτό το αποτέλεσμα... > 6 : (void *) 0x3e2d18 5 : (char *) This is a string 4 : (double) 12.45 3 : (int) 2 2 : (int) 1 1 : (int) 0 press ENTER... Μέχρι εδώ όλα καλά! Το θέμα είναι πως (κι εάν) μπορώ να διαχειριστώ με τρόπο generic τις stack_pop( &stack ) και stack_peek( stack ). Δηλαδή, τι και πώς θα το επιστρέφουν;
παπι Δημοσ. 20 Νοεμβρίου 2011 Δημοσ. 20 Νοεμβρίου 2011 Μαλιστα... Αυτο δεν ειναι generic αλλα object based. Εφοσον δεν εχεις τα εργαλεια, δεν μπορεις να κανεις κατι. Δηλαδη τι θα εκανες; switch(stack_pop_type()) ... case T_CHAR: char c = stack_pop_value() .. ???
migf1 Δημοσ. 21 Νοεμβρίου 2011 Μέλος Δημοσ. 21 Νοεμβρίου 2011 Μαλιστα... Αυτο δεν ειναι generic αλλα object based. Εφοσον δεν εχεις τα εργαλεια, δεν μπορεις να κανεις κατι. Δηλαδη τι θα εκανες; switch(stack_pop_type()) ... case T_CHAR: char c = stack_pop_value() .. ??? Κάτι κατάφερα τελικά. Καταρχήν έκανα την pop() να μην επιστρέφει τίποτα, απλά να καταστρέφει τον πάνω κόμβο. Υπάρχει πρόβλημα στην τιμή επιστροφής, γιατί εμπεριέχει και custom-data που πρέπει να αποθηκευτούν κάπου για να επιστραφούν, πριν γίνουν free. Που σημαίνει πως η ευθύνη της απελευθέρωσης της μνήμης της κόπιας μετατίθεται στον user (εκτός αν τον αναγκάσω να μου περνάει by value παράμετρο στη συνάρτηση... too messy και too inefficient). Tην peek() όμως που δεν χρειάζεται να κάνει free τίποτα, την έβαλα να επιστρέφει έναν δείκτη στο DataType του πάνω κόμβου, δηλαδή έναν δείκτη στο παρακάτω struct (του πάνω κόμβου)... > typedef struct DataType { TypeId typid; union { long double valldouble; char valchar; int valint; double valdouble; } basic; void *pcustom; void (*func_print_custom_data)(void *); } DataType; στο οποίο έβαλα και δείκτη σε user-define ρουτίνα εκτύπωσης (μπορεί να το πάω ένα level πάνω αυτόν τον δείκτη, θα δω). Έχω και μια γενική ρουτίνα εκτύπωσης, τη λέω: dump_stacknode_data( const DataType *pdata ) προς το παρόν, η οποία τυπώνει αυτόματα τα περιεχόμενα είτε είναι basic είτε custom, οπότε π.χ. ο παρακάτω κώδικας... > typedef struct MyData { int varInt; double varDouble; } MyData; void mydata_print( MyData *mydata ) { if ( !mydata ) puts("nothing to print"); printf("int = %d, double = %g\n", mydata->varInt, mydata->varDouble); return; } int main( void ) { StackNode *stack = NULL; MyData mydata = { 100, 9.87 }; char *strtable[]={"hello", "cruel", "bad", "world"}; int i; /* push integers */ for (i=0; i<3; i++) stack_push( &stack, "%d", i ); /* push strings */ for (i=0; i<4; i++) stack_push( &stack, "%s", strtable[i] ); /* push a double, a string and custom data */ stack_push( &stack, "%g", 12.45 ); stack_push( &stack, "%s", "This is a string" ); stack_push( &stack, "%p", &mydata, sizeof(MyData), mydata_print ); /* type agnostic dump of the whole stack */ while ( stack ) { dump_stacknode_data( stack_peek( stack ) ); stack_pop( &stack ); } pressENTER(); stack_destroy( &stack ); exit( EXIT_SUCCESS ); } είναι type agnostic στο printing, και δίνει έξοδο... > (void *) [ 0x3ebfc0 ] int = 100, double = 9.87 (char *) This is a string (double) 12.45 (char *) world (char *) bad (char *) cruel (char *) hello (int) 2 (int) 1 (int) 0 press ENTER... Τώρα για αυτό που με ρώτησες, εφόσον κάθε κόμβος περιέχει data διαφορετικού τύπου, δεν βλέπω κάποιον άλλον τρόπο να μπορούν να κάνουν retrieve τα data, μόνο με switch. Οπότε ναι, κάπως έτσι.... > switch ( stack_peek( stack )->typid ) { case DTYPE_CHAR: c = stack_peek_char( stack ); break; case DTYPE_INT: n = stack_peek_int( stack ); break; ... Οπότε μάλλον θα αντικαταστήσω και τα printf-like specifiers στην stack_push(), αφού θα πρέπει να αποστηθίσουν τα TypeID έτσι κι αλλιώς Δεν βρίσκω κάποιον άλλον τρόπο. Υπάρχει άλλος, έστω κι αν χρειάζεται αλλαγή η δομή του προγράμματος;
bokarinho Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Βρε MigF1, όλα καλά, αλλά κάπου πήρε το μάτι μου ένα framework, πως να δεις το λένε, α ναι, C++ STL. *Γιατί να προσπαθήσουμε να επινοήσουμε ξανά τον τροχό, ποτέ δεν το κατάλαβα...
παπι Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Βρε MigF1, όλα καλά, αλλά κάπου πήρε το μάτι μου ένα framework, πως να δεις το λένε, α ναι, C++ STL. *Γιατί να προσπαθήσουμε να επινοήσουμε ξανά τον τροχό, ποτέ δεν το κατάλαβα... Για εξασκηση; Και btw η STL δεν ειναι framework............................................................................................
bokarinho Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Για εξασκηση; Και btw η STL δεν ειναι framework............................................................................................ Με συγχωρείς μέγα το λάθος μου, κανείς δεν κατάλαβε τι εννοούσα, σωστά είναι software library όπως λέει και το wiki, θα το προσέχω για εσένα την επόμενη φορά (το τι λέω).
παπι Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Με συγχωρείς μέγα το λάθος μου, κανείς δεν κατάλαβε τι εννοούσα, σωστά είναι software library όπως λέει και το wiki, θα το προσέχω για εσένα την επόμενη φορά (το τι λέω). Το καταλαβαμε ολοι οτι μπηκες να κραξεις.
bokarinho Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Δεν νομίζω να μπήκα να κράξω κανέναν, ίσα ίσα που είναι πολύ ενδιαφέρον αυτό που πάει να κάνει ο migf1. Ίσα ίσα που στο πρώτο μου post παραθέτω και κάτι που είχα υλοποιήσει και εγώ κάποτε, αν το πρόσεξες. Η γνώμη μου είναι ότι αυτά υπάρχουν στην C++ με την STL που ενσωματώθηκε σε αυτήν, τώρα εφόσον το θέλει σε C, καλώς, απλά αν αυτό που θέλει δεν ήταν να γίνει οπωσδήποτε σε C, απλά να γίνει, καλό θα ήταν να προσανατολιζόταν ο άνθρωπος προς τα εκεί. Τώρα, παπί, αν εσύ τρώγεσαι με τα ρούχα σου, δεν νομίζω να σου φταίω εγώ, και τις φράσεις σου περί κραξίματος όχι σε εμένα. Ή μάλλον μάθε να διαχωρίζεις το κράξιμο από την κριτική ή την γνώμη που μπορεί να έχει κάποιος άλλος. Και νομίζω πως ξέρουμε ο ένας τον άλλον στο φόρουμ αυτό από παλαιότερα. Για εξασκηση; Και btw η STL δεν ειναι framework............................................................................................ Αλήθεια τα λες καλά; Software framework, a reusable set of libraries or classes for a software system (or subsystem). Άραγε η STL τι είναι; Μήπως μπερδεύεσαι με το Application Framework: .NET / VCL κτλ; Γενικά η STL παπί έχει τα γνωρίσματα ενός Software Framework, οπότε...
migf1 Δημοσ. 21 Νοεμβρίου 2011 Μέλος Δημοσ. 21 Νοεμβρίου 2011 Μου έχει ζητηθεί σε C, και μάλιστα σε C89. Επίσης δεν μου έχουν πει για που προορίζεται, μόνο ότι θέλουν ένα όσο το δυνατόν minimal interface που να διαχειρίζεται και primitive typed και user-defined typed data, με τα primitive να μπορούν να διαχειριστούν και ως values. Και θέλουν ενσωματωμένη τουλάχιστον μια ρουτίνα που θα τυπώνει τα primitive typed data στο forma που πρωτο-εισήχθησαν στον κάθε κόμβο, συν τη δυνατότητα να μπορούν να τα κάνουν fetch από το top node, επίσης στο forma που πρωτο-εισήχθησαν στον κάθε κόμβο. Σε ότι αφορά τα user-defined typed data, τους αρκεί να μπορούν να περνάνε στον κάθε κόμβο μια δικιά τους ρουτίνα εκτύπωσης που θα την χρησιμοποιεί η γενική ρουτίνα εκτύπωσης του interface, συν προφανώς να μπορούν να κάνουν fetch τα data τους από το top-node ανεξάρτητα από την εκτύπωση. ΥΓ1. Ο γνωστός μου που μου το έφερε δουλεύει σε αμερικάνικη εταιρία που ασχολείται με κρυπτογράφηση, αλλά δεν ξέρω αν προορίζεται για εκεί (δεν μου λέει ). ΥΓ2. Btw, υπάρχουν έτοιμες βιβλιοθήκες και στη C, δεν χρειάζεται STL++... πόσταρα ήδη link για την SGLIB, υπάρχει και η GObject (μέρος της GLib)... υπάρχουν κι άλλες. Θέλουν custom και όσο το δυνατόν minimal υλοποίηση. ΥΓ3. (EDIT): Οπότε όπως καταλαβαίνετε, τα type-specifiers α-λα printf τα χρειάζομαι έτσι κι αλλιώς για την εκτύπωση των primitive typed data (και συγκεκριμένα θέλουν η ρουτίνα να τα τυπώνει είτε το ένα κάτω από το άλλο, είτε το ένα δίπλα στο άλλο, με παραμετροποιήσιμο delimiter character (εικάζω πως θα τα βάζουν σε files).
Directx Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 [..]ΥΓ1. Ο γνωστός μου που μου το έφερε δουλεύει σε αμερικάνικη εταιρία που ασχολείται με κρυπτογράφηση, αλλά δεν ξέρω αν προορίζεται για εκεί (δεν μου λέει ).[..] .. embedded System (?)
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα