defacer Δημοσ. 18 Ιανουαρίου 2013 Δημοσ. 18 Ιανουαρίου 2013 Πριν λίγο καιρό αγόρασα το The Practice of Programming των Kernighan και Pike, ένα βιβλίο που κατά πολλούς αξίζει τα μάλα. Ξεφυλλίζοντάς το λίγο πριν πέσω για ύπνο έπεσα πάνω στα παρακάτω αποσπάσματα για τα οποία έχουν γίνει συζητήσεις στο παρελθόν στο φόρουμ. Οι συγγραφείς δεν επεκτείνονται πολύ σ' αυτά γιατί (υποθέτω αλλά και προσωπικά πιστεύω) πρόκειται για "αυτονόητα" πράγματα, αλλά υπάρχει εκτεταμένη επιχειρηματολογία στις συζητήσεις που προανέφερα. Παρόλα αυτά τα παραθέτω εδώ αυτούσια γιατί ναι μεν το να υπάρχουν επιχειρήματα είναι ιδανικό, αλλά και το να συμφωνεί μαζί σου ο Kernighan βοηθάει κάπως. 1.4. Function macros There is a tendency among older C programmers to write macros instead of functions for very short computations that will be executed frequently; I/O operations such as getchar and character tests like isdigit are officially sanctioned examples. The reason is performance: a macro avoids the overhead of a function call. This argument was weak even when C was first defined, a time of slow machines and expensive function calls; today it is irrelevant. With modern machines and compilers, the drawbacks of function macros outweigh their benefits. Avoid function macros. In C++, inline functions render function macros unnecessary; in Java, there are no macros. In C, they cause more problems than they solve. 1.5. Magic numbers Define numbers as constants, not macros. C programmers have traditionally used #define to manage magic number values. The C preprocessor is a powerful but blunt tool, however, and macros are a dangerous way to program because they change the lexical structure of the program underfoot. Let the language proper do the work. In C and C++, integer constants can be defined with an enum statement, as we saw in the previous example. Constants of any type can be declared with const in C++ or final in Java. C also has const values but they cannot be used as array bounds, so the enum statement remains the method of choice in C. Την επόμενη φορά που θα πάτε να γράψετε #define, σκεφτείτε: μήπως υπάρχει καλύτερος τρόπος; 3
Directx Δημοσ. 18 Ιανουαρίου 2013 Δημοσ. 18 Ιανουαρίου 2013 (επεξεργασμένο) Κοίταξε να δεις σύμπτωση! Όσον αφορά τις inline functions αυτές τις μέρες γράφω ένα υποσύστημα του λογισμικού μου στο οποίο η χρήση inline συναρτήσεων (για κάποιους λόγους) είναι απαραίτητη. Η πρώτη σκέψη ήταν φυσικά η δήλωση των εν λόγο συναρτήσεων ως inline ώστε ο compiler να παράγει ανάλογο κώδικα. Ελέγχοντας σε επίπεδο assembly όμως το εκτελέσιμο με απογοήτευση διαπίστωσα ότι ο μεταφραστής αγνόησε την σήμανση inline , ο κώδικας ήταν σαφέστατα βελτιστοποιημένος αλλά οι συναρτήσεις που ήθελα υποχρεωτικά ως inline κώδικα δεν είχα γίνει inlined τελικά. Ψάχνοντας την τεκμηρίωση του μεταφραστή διαπίστωσα ότι η σήμανση inline είναι ένα hint προς τον compiler για το τι πρέπει να κάνει και όχι δέσμευση, συνεπώς αν ήθελα υποχρεωτικά την δήλωση των συναρτήσεων αυτών σε μορφή inline θα έπρεπε να καταλήξω στην χρήση macro functions. Άρα από την παραπάνω εμπειρία μου καταλήγω στο συμπέρασμα ότι ναι σε θεωρητικό επίπεδο πράγματι το inline οφείλει να είναι αρκετό (και πολύ καλύτερο από τα άχαρα macro functions) όπως υποδεικνύουν οι συγγραφείς αλλά σε πρακτικό επίπεδο δεν μπορεί να είσαι σίγουρος (ας είσαι και ο Kernighan..) πως δρα ο κάθε compiler, οπότε η χρήση macros είναι μάλλον η πιο σίγουρη λύση. Επεξ/σία 18 Ιανουαρίου 2013 από Directx 2
defacer Δημοσ. 18 Ιανουαρίου 2013 Μέλος Δημοσ. 18 Ιανουαρίου 2013 Το ότι το inline είναι hint προς τον compiler και δεν επιτρέπει τον απόλυτο έλεγχο του τι συμβαίνει (σε κανένα compiler που γνωρίζω) είναι ευρέως γνωστό, και είναι αφελές να πιστεύουμε πως δεν το ξέρουν και οι συγγραφείς. Όπως είπα όμως οι τελευταίοι δεν επεκτείνονται, και όπως δεν είπα αλλά είναι σίγουρα προφανές άλλο το "μην το κάνεις αυτό γιατί σε σκότωσα" και άλλο το "απέφυγέ το όσο περισσότερο μπορείς" (γιατί αυτό λέει παραπάνω). Αυτά σχετικά με το γράμμα του νόμου. Όσον αφορά συγκεκριμένα το θέμα του inline, θα επεκταθώ εν συντομία για να καλύψω τα κενά. 1. Η προσπάθεια χρήσης του inline (και κάθε άλλου optimization) για να τρέξει πιο γρήγορα το πρόγραμμα είναι τελείως λανθασμένη εκτός και αν συνοδεύεται από profiling. Θα μπορούσα να βρω άπειρες αναφορές, ένα γρήγορο googling μου βρήκε το εξής από το Code Complete (ακόμα μεγαλύτερο τιτανοβιβλίο) -- δες στο κάτω μέρος της σελίδας 594. Αν είναι απαραίτητο μπορώ σίγουρα να κάνω κάτι καλύτερο όταν βρω χρόνο. Παρεμπιπτόντως το ίδιο ή ίσως και ακόμα χειρότερο είναι το να δηλώνει κανείς μεταβλητές ως register, η γενική ιδέα είναι ακριβώς η ίδια και μόνο κάποιες τεχνικές λεπτομέρειες διαφέρουν λίγο (χωρίς όμως να αλλάζει στο ελάχιστο η ουσία του τι συμβαίνει). 2. Ακόμα και αν το inline πετύχει και όντως γλυτώσεις το overhead του function call και όντως αυτό ήταν στο critical path της εφαρμογής και όντως ήταν το καλύτερο optimization που μπορούσες να κάνεις (γιατί αν δεν ήταν απλά δεν ξοδεύεις σωστά το χρόνο σου), και πάλι δεν είναι σίγουρο πως το πρόγραμμα σαν σύνολο θα τρέχει γρηγορότερα. Κι αυτό γιατί, όπως επίσης είναι ευρέως γνωστό, πολλές φορές κώδικας που είναι μικρότερος σε μέγεθος τρέχει ασύγκριτα γρηγορότερα επειδή χωράει "καλύτερα" στις caches του επεξεργαστή. Όταν μια συνάρτηση γίνεται inlined τότε ο κώδικάς της μπαίνει σε κάθε ένα call site ξεχωριστά, επομένως το μέγεθος του εκτελέσιμου κώδικα αυξάνει και αν αυτό βγάλει το critical path ή μέρος του από την L1 της CPU η ταχύτητα πάει περίπατο. Προφανώς είναι βέβαιο πως μιλάμε για πολλαπλά call sites γιατί αν δεν ήταν έτσι τότε και ο compiler θα την έκανε inline πολύ ευκολότερα και επίσης θα ήταν δυνατό να την κάνει και ο developer inline "manually". Δεν είμαι λοιπόν σίγουρος για ποιό λόγο η χρήση της inline στην περίπτωσή σου ήταν απαραίτητη. Εφόσον όμως ήταν και εφόσον δε μπορούσες να βάλεις τον compiler να κάνει inline με τίποτα και εφόσον δεν υπήρχε κάποια άλλη λύση που να πετυχαίνει το επιθυμητό αποτέλεσμα, καλά έκανες και έβαλες macro. Το point μου είναι πως αυτά είναι πολλά "εφόσον" για να πετάμε macros αδιάκριτα, και είμαι σίγουρος πως η παραπάνω ανάλυση δεν περιέχει κάτι που ο Kernighan αλλά και πολύ λιγότερο μεγάλα ονόματα απ' το δικό του δε γνωρίζουν.
Directx Δημοσ. 18 Ιανουαρίου 2013 Δημοσ. 18 Ιανουαρίου 2013 Το point μου είναι πως αυτά είναι πολλά "εφόσον" για να πετάμε macros αδιάκριτα, και είμαι σίγουρος πως η παραπάνω ανάλυση δεν περιέχει κάτι που ο Kernighan αλλά και πολύ λιγότερο μεγάλα ονόματα απ' το δικό του δε γνωρίζουν.Σωστά τα παραπάνω, αλλά εγώ δεν κάνω inline για λόγους optimization συνεπώς δίχως macro αυτό που πρέπει να γίνει δεν θα μπορούσε να γίνει καθόλου κομψά (σε επίπεδο πηγαίου κώδικα). Anyway, νομίζω ότι το θέμα εξαντλήθηκε - αν κρίνεις ότι έχεις καλούς λόγους να χρησιμοποιήσεις υποχρεωτικά (το τονίζω αυτό υποχρεωτικά & τεκμηριωμένα) inline κώδικα στο λογισμικό σου εξέτασε το εκτελέσιμο αν ο compiler δεν σεβαστεί την επιθυμία σου (inline) τότε macro.
migf1 Δημοσ. 18 Ιανουαρίου 2013 Δημοσ. 18 Ιανουαρίου 2013 Έχουμε ήδη εξαντλήσει τα υπέρ και τα κατά των macros. Αν ξέρεις τι κάνεις, σου δίνουν ευελιξία, ισχύ και ταχύτητα πέρα από τις κλασικές δυνατότητες της γλώσσας. Πέρα από το forced inlining no matter what, πολυμορφισμός, overloading και code-generation είναι μερικοί ακόμα πολύ χαρακτηριστικοί λόγοι για να χρησιμοποιεί κανείς macros στην C. Good reads: 1. http://multi-core-dump.blogspot.gr/2010/11/interesting-use-of-c-macros-polymorphic.html 2. http://stackoverflow.com/questions/653839/what-are-c-macros-useful-for 3. https://blogs.oracle.com/ksplice/entry/8_gdb_tricks_you_should (Νούμερο 5) ΥΓ. Είναι από άκομψο έως και άστοχο να χαρακτηρίζουμε ως "κακή συνήθεια" π.χ. παραπάνω από το μισό code-base των Linux internals (και μυριάδων άλλων C APIs και μη) που είναι χτισμένα πάνω σε macros. EDIT: Παρεμπιπτόντως, για μια ακόμα φορά: http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=ansi#constasconst 1
Directx Δημοσ. 18 Ιανουαρίου 2013 Δημοσ. 18 Ιανουαρίου 2013 Ξέχασες τον Thompson, σίγουρα και αυτός θα έχει κάτι να πει.. (humor κάνω μην παρεξηγηθείς)
defacer Δημοσ. 18 Ιανουαρίου 2013 Μέλος Δημοσ. 18 Ιανουαρίου 2013 Ξέχασες τον Thompson, σίγουρα και αυτός θα έχει κάτι να πει.. Όντως... ας όψεται το K&R που έχει μείνει στην ιστορία. Όλα αυτά τα παλικάρια ήταν "μια παρέα"... και ο Pike που ανέφερα στην αρχή δεν είναι κανένας τυχαίος. Μάλιστα (μια παρέα που έλεγα) ο Pike μαζί με τον Thompson σχεδίασαν το UTF-8. Έτυχε κάποτε να διαβάσω σε μια συνέντευξη, του Pike νομίζω, ότι το συζητούσαν μετά το φαΐ και κρατούσαν σημειώσεις στις χαρτοπετσέτες γιατί δεν είχαν μαζί σημειωματάριο. Αυτό θα πει nerd bliss. Αλλά πραγματικά με τέτοια φάτσα που πας ρε Ken?
Directx Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 Όντως... ας όψεται το K&R που έχει μείνει στην ιστορία. Όλα αυτά τα παλικάρια ήταν "μια παρέα"... και ο Pike που ανέφερα στην αρχή δεν είναι κανένας τυχαίος. Μάλιστα (μια παρέα που έλεγα) ο Pike μαζί με τον Thompson σχεδίασαν το UTF-8. Έτυχε κάποτε να διαβάσω σε μια συνέντευξη, του Pike νομίζω, ότι το συζητούσαν μετά το φαΐ και κρατούσαν σημειώσεις στις χαρτοπετσέτες γιατί δεν είχαν μαζί σημειωματάριο. Αυτό θα πει nerd bliss.Ενδιαφέρον, μου θυμίζει την θρυλική σουπλά (ή σουβέρ -το χαρτί που μπαίνει κάτω από το πιάτο σε διάφορα εστιατόρια ώστε να μην λερωθεί το τραπεζομάντιλο) πάνω στην οποία λέγεται ότι σχεδιάστηκε η μορφή του Compaq Portable, του πρώτου εύκολα μεταφερόμενου IBM συμβατού.Αλλά πραγματικά με τέτοια φάτσα που πας ρε Ken? Χε.. χε.. πριν χρόνια έτυχε να γνωρίσω έναν τύπο που είχε συνεργαστεί με τον Thompson και ή με τον Ritchie ή με τον Kernigham (δεν θυμάμαι με ποίον από τους άλλους δυο :-/), μου έλεγε ότι ο Thompson ήταν δύσκολος χαρακτήρας, αντίθετα ή ο Ritchie ή ο Kernighan ήταν "ψυχούλα".
gdelaportas Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 Let me be the Devils Advocate for a bit... Αλλά, ποιός ακριβώς θέτει τους κανόνες για το τί πρέπει και δεν πρέπει στο development και πως αυτό μεταφράζεται σαν "νόμος"? Δηλαδή "according to who" κάτι είναι rule? Σε όσα βιβλία και αν έχω διαβάσει σε όσα sources σέβονται τον εαυτό τους στο Internet όλοι λένε την φράση: "Informatics and Engineering is the Science and ART" Δηλαδή, ποιος θα θέσει στον καλλιτέχνη όρια και περιμένει μετά να είναι αποδοτικός και να παράγει ένα ορθό αποτέλεσμα. Αυτό επίσης είναι σπόντα και για όσους λυσάνε για τους οπτικούς τρόπους καλής γραφής κώδικα. Δηλαδή ακούω και μου λένε: ά αφήνεις κενό κάτω από την προηγούμενη γραμμή, ά γιατί το άγκιστρο δεν είναι δίπλα στο function, ά γιατί γράφεις έτσι τα σχόλια... Αυτά, είναι ΑΣΤΕΙΑ πράγματα. Εάν δείτε πραγματικά commercial enterprise κώδικα από λογισμικά χωρισμένα σε modules θα δείτε μεν μια ομοιομορφία αλλά γενικά ο κάθε προγραμματιστής έχει βάλει την δικιά του "πένα" μέσα... Επιπλέον, στην εποχή μας είναι αστείο να μιλάμε για optimizations σε ταχύτητες που μπορεί με το ζόρι να κάνουν μια διαφορά της τάξης του 100μsec - 10msec. TOTALLY IRRELEVANT! Εκτός και αν βέβαια μιλάμε για mission critical apps οπότε εκεί πάω πάσσο αλλά και εκεί ακόμα παίζεις αλλιώς. Δηλαδή με Ada και SPARK και δεν χρειάζεται by design να κάθεσε να λιώνεις για την ταχύτητα και πώς θα το πετύχεις. Αυτές οι γλώσσες έχουν a priori constraints και scenarios από τα οποία δε ξεφεύγεις γιατί είναι για auto-pilots, military and space technologies.
gdelaportas Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 @imitheos αποψή σου... Από τη δική μου εμπειρία πάντως τα πράγματα στην πραγματική ζωή και στου χώρους εργασίας δεν είναι και τόσο κοντά όπως στον εικονικό κόσμο.
imitheos Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 @imitheos αποψή σου...Φυσικά. Ο καθένας παραθέτει την δική του άποψη των πραγμάτων. Από τη δική μου εμπειρία πάντως τα πράγματα στην πραγματική ζωή και στου χώρους εργασίας δεν είναι και τόσο κοντά όπως στον εικονικό κόσμο. Επειδή δεν έχω μεγάλη εμπειρία από την πραγματική ζωή και τους χώρους εργασίας, θα μπορούσες να μας πεις σε ποιο χώρο εργασίας το παρακάτω όχι μόνο είναι αποδεκτό αλλά θεωρείται και art ? /* AAL - Copy */ char *aal_copy(char *S, unsigned long P) { uintptr_t LenS; char *N; char *CRes = aal_mem_alloc_1(S); N = S; LenS = aal_len(S); while (((P + (N - S)) < LenS) && (isdigit(S[P + (N - S)]) || S[P + (N - S)] == '-' || S[P + (N - S)] == '.')) { CRes[N - S] = S[P + (N - S)]; *N++; } CRes[N - S] = '\0'; return CRes; }
Directx Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 (επεξεργασμένο) Έχω την εντύπωση πως ο Ritchie πρέπει να ήταν (ή τουλάχιστον αυτός). Πολύς κόσμος τον παρουσίαζε ως δεκτικό και συζητήσιμο άνθρωπο χωρίς εγωισμό τύπου "εγώ είμαι και άλλος δεν υπάρχει".Κατά βάθος και εγώ πιστεύω ότι αναφερόταν στον Ritchie (κρίμα να μην κρατήσω μια σημείωση τότε επ' αυτού :-/). Επεξ/σία 19 Ιανουαρίου 2013 από Directx
παπι Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 Ίσα ίσα, που το παραπάνω είναι και καλά δομημένο και clean, άλλα να δεις... Αυτό που κάνει είναι να αντιγράφει ένα C string (char *) σε ένα άλλο χωρίς τις τελείες (.) και τα μείον (-). Είναι μέρος ενός μεγαλύτερου προγράμματος τέλος πάντων για πράξεις σε arbitrary numbers με βάση τα strings. Clean??? Μας κανεις πλακα. Οκ, η c δεν φημιζεται για τα περιγραφηκα ονοματα, αλλα ειπαμε, οχι και ετσι. Ενα γραμμα ολο κι ολο και αυτο κεφαλαιο; Oριστε ενα clean size_t copy1(const char *source,char *dest) { size_t count = 0; for(;*source; ++source) { if( *source == '.' || *source == '-' || 0 /*etc..*/) continue; count++; *dest++ = *source; } *dest++ = 0; return count; } 1
gdelaportas Δημοσ. 19 Ιανουαρίου 2013 Δημοσ. 19 Ιανουαρίου 2013 Clean??? Μας κανεις πλακα. Οκ, η c δεν φημιζεται για τα περιγραφηκα ονοματα, αλλα ειπαμε, οχι και ετσι. Ενα γραμμα ολο κι ολο και αυτο κεφαλαιο; Oριστε ενα clean size_t copy1(const char *source,char *dest) { size_t count = 0; for(;*source; ++source) { if( *source == '.' || *source == '-' || 0 /*etc..*/) continue; count++; *dest++ = *source; } *dest++ = 0; return count; } Μάλιστα... δηλαδή αυτό τι διαφορά έχει κατ' εσένα... αυτό ας πούμε διαβάζεται μόνο και μόνο επειδή έχει λέξεις ε? Ένα έμπειρος προγραμματιστής όμως ξέρει τί είναι το p για το pointer το C γιατ το counter και τα συναφή. Εν τη αύτη περιπτώση, δε θα διαφωνήσω ότι εάν ήμουν με ομάδα θα ήταν σίγουρα πιο περιγραφικά τα ονόματα. Από εκεί και πέρα τώρα, ο λόγος που εγώ απαντάω έτσι είναι όχι γιατί τα έχω με κανέναν σας. Ούτε τη θέση θα μου φάτε, ούτε χωράφια έχουμε να χωρίσουμε, όυτε σας ξέρω και με ξέρετε. Απλά, θέλω να ξεκολήσετε και να κατανοήσετε επιτέλους ότι η τεχνολογία (υλικό, λογισμικό και προγραμματισμός...) είναι το μέσον και όχι το αποτέλεσμα. Με άλλα λόγια εάν κάτι δουλεύει και έχετε επιλέξει το τάδε εργαλείο όπως η C, δε νοιάζεται στο production κανείς μα κανείς αν το γράψατε εσείς με τους super τρομακτικούς αυστηρούς και με βάση τις πιο τέλειες πρακτικές τρόπους σας, ούτε αν το έγραψαν μαϊμούδες για εσάς!!!! Το μόνο που τους νοιάζει είναι να δουλεύει όπως πρέπει και να είναι σταθερό για να πουληθεί! Εάν μετά εσείς θέλετε να κάνετε την πλάκα σας και να λιώνετε για να το κάνετε super code, DO IT και ένα μεγάλο ΜΠΡΑΒΟ! Όμως, δε μπορώ να ακούω ιστορίες από άτομα που ΔΕΝ είναι στην παραγωγή κάθε μέρα... και ΝΑΙ όπως λέει και ο @mifg1 υπάρχουν τεράστια λογισμικά και ανοικτού κώδικα μάλιστα που έχουν μέσα "κακό" κώδικα από άποψη δομής, ομορφιάς αρχιτεκτονικής... αλλά κάνουν αυτό που πρέπει να κάνουν και το κάνουν καλά. Οπότε τι διάολο ζητάτε? Θέλετε ένα productive λογισμικό ή μια έκθεση για να την δείχνετε στους φίλους σας. Εδώ είναι το ερώτημα! Νομίζω πως εδώ μπαίνει το επιχειρείν στη μέση και γι αυτό έχουμε τόσο μεγάλο χάσμα και διαφορές στη φιλοσοφία μας. Το καταλαβαίνω...
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα