Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.
[..]Όπου, ένα enum με τιμές 1, 2, 3, 4, κτλ... δεν είναι τόσο safe όσο ένα #define με τιμές 0x00, 0xA0, 0x10 και ό,τι άλλο. Όχι απλά δεν είναι τόσο safe, αλλά αναλόγως και τον εκάστοτε compiler του vendor (ειδικά σε embedded systems) μπορεί να μην έχεις ακριβή έλεγχο στον buffer που θες να γεμίσεις με συγκεκριμένες τιμές εάν χρησιμοποιήσεις enums... ή να κάνεις το λάθος και να μην βάλεις cast. Άρα, εκεί κερδίζει το #define και χάνει το enum.

Με έβαλες σε σκέψεις - σε C++ Builder πάντως με μια γρήγορη ματιά τόσο οι τιμές οριζόμενες ως #DEFINE όσο και οι τιμές οριζόμενες μέσο enum επιστρέφουν κοινό native κώδικα (από ότι βλέπω μέσο dis-assembler).

 

Τώρα για άλλους compilers δεν μπορώ να πω τίποτα -ενδιαφέρουσα πάντως παρατήρηση! ;)

  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

Με έβαλες σε σκέψεις - σε C++ Builder πάντως με μια γρήγορη ματιά τόσο οι τιμές οριζόμενες ως #DEFINE όσο και οι τιμές οριζόμενες μέσο enum επιστρέφουν κοινό native κώδικα (από ότι βλέπω μέσο dis-assembler).

 

Τώρα για άλλους compilers δεν μπορώ να πω τίποτα (ενδιαφέρουσα πάντως παρατήρηση ;)).

 

 

Με compiler του IAR IDE υπάρχει διαφορά (π.χ.)

Δημοσ.

Υποθέτω αναφέρεται σε αυτό που έθιξα κι εγώ παραπάνω για τα bits, ότι δηλαδή δεν μπορείς να βασιστείς στο enum για να υλοποιήσεις bit-values μεγαλύτερες του platform-dependent implementation των int (μιας και τα enum γίνονται treat ως int). Π.χ. σε 4-byte int με enum μπορείς να πας το πολύ μέχρι 2^31.

Ναι, αλλά ας μη ξεχνάμε ότι το enum το προμοτάρουμε για 2 πολύ συγκεκριμένες περιπτώσεις:

 

  1. Για χρήση σα μέγεθος πίνακα
  2. Για χρήση μέσα σε switch case

Για όλες τις άλλες περιπτώσεις μπορούμε να κάνουμε τη δουλειά με constant που είναι ακόμα καλύτερο γιατί δεν έχει αυτό το πρόβλημα!

 

Δεδομένου τώρα ότι για μέγεθος fixed πίνακα δεν το κόβω και πολύ πιθανό να το θέλεις μεγαλύτερο από 2 δισεκατομμύρια, και ότι επίσης δυσκολεύομαι να φανταστώ switch με πάνω από 2 δισεκατομμύρια case, γιατί είπαμε ότι είναι καλή ιδέα το macro (αντί για const αυτή τη φορά)?

 

@Timonkaipumpa: απάντησες όσο έγραφα :) είδα την απάντησή σου, δες και συ το παραπάνω και θα ήθελα την τοποθέτησή σου πάνω σ' αυτό.

 

Edit: Προφανώς τα δισεκατομμύρια παραπάνω τώρα που το ξανασκέφτομαι δεν είναι fixed δισεκατομμύρια γιατί σε embedded πολύ πιθανό να έχεις sizeof(int) == 2 (βεβαίως θα έχεις και λιγότερη μνήμη οπότε πάλι μπορεί να σε καλύπτει το enum όσον αφορά τους πίνακες -- για το switch δεν κάνει καμία διαφορά). Επομένως δεκτή η ένσταση ότι μπορεί να μη σου φτάνει το εύρος του int σε κάποιες περιπτώσεις embedded development συγκεκριμένα -- εκεί φανερά δεν υπάρχει άλλη λύση από macro.

Δημοσ.

Με έβαλες σε σκέψεις - σε C++ Builder πάντως με μια γρήγορη ματιά τόσο οι τιμές οριζόμενες ως #DEFINE όσο και οι τιμές οριζόμενες μέσο enum επιστρέφουν κοινό native κώδικα (από ότι βλέπω μέσο dis-assembler).

 

Τώρα για άλλους compilers δεν μπορώ να πω τίποτα -ενδιαφέρουσα πάντως παρατήρηση! ;)

Πρέπει να παίζει ρόλο ότι στα Windows ο int είναι fixed στα 2 bytes, no matter what. Από περιέργεια, για δοκίμασε να κάνεις #define μια τιμή που αντιστοιχεί ας πούμε σε 8 bytes.

Δημοσ.

@defacer

Προσωπικά, δεν βρίσκω "κακή" την χρήση του enum όπου χρειάζεται. Οι περιπτώσεις που αναφέρεις, εάν δεν σχετίζονται με όσα έγραψα (ήτοι, πολύ συγκεκριμένες τιμές σε buffers ή από buffers/interfaces με τον έξω κόσμο), νομίζω ότι βολεύουν με το enum.

 

Μία ακόμα περίπτωση που εγώ θα χρησιμοποιούσα enum αντί για #define είναι για τιμές που εννοιολογικά ανήκουν σε μία ομάδα και δεν πρόκειται να αυξηθούν μετά.

 

Π.χ.

 

ISNEGATIVE

ISZERO

ISPOSITIVE

 

Πολύ άχαρο παράδειγμα.. αλλά νομίζω δείχνει τι εννοώ.

 

Αν και, με τα structs η C προσφέρει κάτι που δεν έχει κάποια άλλη γλώσσα (από όσο ξέρω) σχετικά με μεταβλητούς πίνακες, and that is incomplete structs. Γιατί λοιπόν να χρησιμοποιείς enums για μεγέθη πίνακα ενώ μπορείς να έχεις μία δομή που να διαχειρίζεται ταμάμ τους πίνακες και να παίρνει μνήμη για πίνακα μόνο όπου χρειάζεται;

 

Π.χ.

 

>

struct FooStuct{
 int size;
 int* theArray;
}

 

Λιγότερες γραμμές παραπάνω κώδικα και έχεις όσο μέγεθος θες έτοιμο :P

Και αφήνεις το ΛΣ να σου δώσει μνήμη, όπου έχει, εάν έχει.

 

 

edit και εγώ :P

Δεν είναι τόσο το εύρος.. είναι η ακριβής τιμή. Όταν το rf module μεταδίδει συγκεκριμένες τιμές, εάν περιμένεις unsigned και σου έρθει signed, την έκατσες. Πώς το εξασφαλίζεις αυτό με το enum, δεδομένης της παράθεσης που έκανα; Θα μπορούσες να πεις με casts. Όμως εκεί δεν πέφτει κανείς πάλι στο λάθος του γραψίματος; Ένα cast να σου ξεφύγει, μπορεί να το ψάχνεις 2 εβδομάδες... με άπειρα deubgs και monitoring του τι περιέχει κάθε buffer σε κάθε στοιχείο του.

Δημοσ.

...

Δεδομένου τώρα ότι για μέγεθος fixed πίνακα δεν το κόβω και πολύ πιθανό να το θέλεις μεγαλύτερο από 2 δισεκατομμύρια, και ότι επίσης δυσκολεύομαι να φανταστώ switch με πάνω από 2 δισεκατομμύρια case, γιατί είπαμε ότι είναι καλή ιδέα το macro (αντί για const αυτή τη φορά)?

...

@Timonkaipumpa: απάντησες όσο έγραφα :) είδα την απάντησή σου, δες και συ το παραπάνω και θα ήθελα την τοποθέτησή σου πάνω σ' αυτό.

 

Edit: Προφανώς τα δισεκατομμύρια παραπάνω τώρα που το ξανασκέφτομαι δεν είναι fixed δισεκατομμύρια γιατί σε embedded πολύ πιθανό να έχεις sizeof(int) == 2 (βεβαίως θα έχεις και λιγότερη μνήμη οπότε πάλι μπορεί να σε καλύπτει το enum όσον αφορά τους πίνακες -- για το switch δεν κάνει καμία διαφορά). Επομένως δεκτή η ένσταση ότι μπορεί να μη σου φτάνει το εύρος του int σε κάποιες περιπτώσεις embedded development συγκεκριμένα -- εκεί φανερά δεν υπάρχει άλλη λύση από macro.

 

Είπαμε ότι το #define είναι καλύτερο του enum σε αυτή την περίπτωση, και όχι του const (3-4 ποστς δεν έγραφες πως προωθείς το enum και όχι το const); Και για τη συγκεκριμένη περίπτωση δεν αναφερόμαστε στην τιμή απεικόνισης αυτή κάθε αυτή, αλλά στο platform-dependent οριοθετημένο πλήθος των bits που μπορείς να διαχειριστείς με το enum... π.χ. σε bitmasks.

Δημοσ.

Προσωπικά, δεν βρίσκω "κακή" την χρήση του enum όπου χρειάζεται. Οι περιπτώσεις που αναφέρεις, εάν δεν σχετίζονται με όσα έγραψα (ήτοι, πολύ συγκεκριμένες τιμές σε buffers ή από buffers/interfaces με τον έξω κόσμο), νομίζω ότι βολεύουν με το enum.

Νομίζω ότι δεν κατάλαβες πώς το εννούσα. Το enum είπαμε που είναι ταμάμ (σε μεγέθη πίνακα και switch case). Για τα υπόλοιπα, όπως το παράδειγμα που είχες δώσει πριν με τα unsigned char, η γλώσσα επιτρέπει τη χρήση const που για μένα είναι ακόμα προτιμότερο (ψοφήσαμε να μιλάμε για enum γιατί ο migf1 έφερε το παράδειγμα με το μέγεθος πίνακα όπου το const δε φτουράει, αλλίως const FTW).

 

Αν και, με τα structs η C προσφέρει κάτι που δεν έχει κάποια άλλη γλώσσα (από όσο ξέρω) σχετικά με μεταβλητούς πίνακες, and that is incomplete structs. Γιατί λοιπόν να χρησιμοποιείς enums για μεγέθη πίνακα ενώ μπορείς να έχεις μία δομή που να διαχειρίζεται ταμάμ τους πίνακες και να παίρνει μνήμη για πίνακα μόνο όπου χρειάζεται;

Γιατί ο migf1 έφερε το παράδειγμα με τους fixed πίνακες και όφειλα να του απαντήσω πάνω σ' αυτό. :) Διαφορετικά εννοείται πως βάλε malloc και κάνε ό,τι τραβάει η ψυχή σου.

 

Είπαμε ότι το #define είναι καλύτερο του enum σε αυτή την περίπτωση, και όχι του const (3-4 ποστς δεν έγραφες πως προωθείς το enum και όχι το const); Και για τη συγκεκριμένη περίπτωση δεν αναφερόμαστε στην τιμή απεικόνισης αυτή κάθε αυτή, αλλά στο platform-dependent οριοθετημένο πλήθος των bits που μπορείς να διαχειριστείς με το enum... π.χ. σε bitmasks.

Προωθώ το enum και όχι το const στις 2 συγκεκριμένες περιπτώσεις όπου το const δε μπορεί να βγάλει τα κάστανα απ' τη φωτιά, πράγμα που είμαι αναγκασμένος να κάνω εφόσον φέρνεις τέτοιο παράδειγμα. Διαφορετικά const ασυζητητί εφόσον η λογική μου παραμένει "το πιο κατάλληλο εργαλείο για τη συγκεκριμένη δουλειά και όχι κάτι παραπάνω".

 

Φαντάζομαι μπορείς να οπτικοποιήσεις πως αν είχα αρχίσει να λέω ότι const uber alles θα μου κοπανούσες το παράδειγμα του VLA μέχρι ν' ασπρίσουν τα γένια μας.

Δημοσ.

Προωθώ το enum και όχι το const στις 2 συγκεκριμένες περιπτώσεις όπου το const δε μπορεί να βγάλει τα κάστανα απ' τη φωτιά, πράγμα που είμαι αναγκασμένος να κάνω εφόσον φέρνεις τέτοιο παράδειγμα. Διαφορετικά const ασυζητητί.

Σκέτο ή static? (πρόσεξε τι θα απαντήσεις, είναι παγίδα :lol:).

 

Σοβαρά τώρα, πιστεύεις στις μαγικές συνταγές, εγώ όχι. Δεν χρειάζεται να συμφωνήσουμε ;)

Δημοσ.

Νομίζω ότι δεν κατάλαβες πώς το εννούσα. Το enum είπαμε που είναι ταμάμ (σε μεγέθη πίνακα και switch case). Για τα υπόλοιπα, όπως το παράδειγμα που είχες δώσει πριν με τα unsigned char, η γλώσσα επιτρέπει τη χρήση const που για μένα είναι ακόμα προτιμότερο (ψοφήσαμε να μιλάμε για enum γιατί ο migf1 έφερε το παράδειγμα με το μέγεθος πίνακα όπου το const δε φτουράει, αλλίως const FTW).

 

 

Χμ..

 

Ναι, έχεις δίκιο ότι δεν το κατάλαβα ακριβώς.

 

Όμως, μετά την διευκρίνιση, να σου δώσω ένα παράδειγμα.

 

Έστω ότι έχεις ένα project, για τον client και για τον server. Υπάρχει ένα συγκεκριμένο μέγεθος για κάποιον header (που μπαίνει σε buffer), σε ένα συγκεκριμένο τύπο μηνύματος.

 

Το μέγεθος θα το βάλεις σε enum ή σε #define;

 

Όταν θες αυτό το project να είναι ανεξάρτητο από vendor CPU, compiler και ό,τι άλλο και να μπορεί να υπακούει και σε κουλά "πρότυπα" (π.χ. MISRA C).

 

Προσωπικά, και όπως έχω δει, θα το έβαζα σε #define.

Δημοσ.

Σοβαρά τώρα, πιστεύεις στις μαγικές συνταγές, εγώ όχι. Δεν χρειάζεται να συμφωνήσουμε ;)

 

Νομίζω πως η άποψή μου είναι ξεκάθαρη (και το γιατί τεκμηριωμένο), θα τη συνοψίσω κι εδώ για να συνεννοούμαστε:

 

  1. If η δουλειά γίνεται με const τότε const
  2. Else if η δουλειά γίνεται με enum τότε enum
  3. Else με macro

Αν αυτό θέλεις να το βαφτίσεις μαγική συνταγή πάω πάσο. Εγώ το βαφτίζω επιστημονικό τρόπο λήψης αποφάσεων γιατί είναι 100% ντετερμινιστικός.

Δημοσ.

Νομίζω πως η άποψή μου είναι ξεκάθαρη (και το γιατί τεκμηριωμένο), θα τη συνοψίσω κι εδώ για να συνεννοούμαστε:

 

  1. If η δουλειά γίνεται με const τότε const
  2. Else if η δουλειά γίνεται με enum τότε enum
  3. Else με macro

Αν αυτό θέλεις να το βαφτίσεις μαγική συνταγή πάω πάσο. Εγώ το βαφτίζω επιστημονικό τρόπο λήψης αποφάσεων γιατί είναι 100% ντετερμινιστικός.

Μα αφού το #define σου παρέχεται δωρεάν και οι περιπτώσεις που καλύπτει είναι περισσότερες και από τις περιπτώσεις που καλύπτει το const και από τις περιπτώσεις που καλύπτει το enum (με άλλα λόγια είναι το πιο ευέλικτο από όλα) :lol:

 

Κοίτα, πέρα από την πλάκα και τα πειράγματα, αυτό που καταλαβαίνω είναι πως η οπτική σου γωνία σε όλες σου τις τοποθετήσεις (ή έστω στις περισσότερες) είναι επηρεασμένη από την μεγαλύτερη επαφή που έχεις με strict-ruled προγραμματισμό, ενώ αντίθετα η δική μου είναι επηρεασμένη από την μεγαλύτερη επαφή που έχω με lose-ruled προγραμματισμό.

 

Από εκεί πιστεύω πηγάζει το μεγαλύτερο μέρος των κατά καιρούς διαφωνιών μας, έντονων και ήπιων. Από τη στιγμή που μπορέσουμε να κρατήσουμε ένα πολιτισμένο κι εποικοδομητικό επίπεδο στις διαφωνίες μας, δεν νομίζω πως χρειάζεται να συμφωνούμε... και κυρίως δεν νομίζω πως βλάπτει και την συζήτηση (αντίθετα πιστεύω την οφελεί).

Δημοσ.

Έστω ότι έχεις ένα project, για τον client και για τον server. Υπάρχει ένα συγκεκριμένο μέγεθος για κάποιον header (που μπαίνει σε buffer), σε ένα συγκεκριμένο τύπο μηνύματος.

 

Το μέγεθος θα το βάλεις σε enum ή σε #define;

 

Όταν θες αυτό το project να είναι ανεξάρτητο από vendor CPU, compiler και ό,τι άλλο και να μπορεί να υπακούει και σε κουλά "πρότυπα" (π.χ. MISRA C).

Ενδιαφέρον παράδειγμα. Μιας και μιλάμε αποκλειστικά για fixed size array (το ξεκαθαρίσαμε παραπάνω) σίγουρα το πρόγραμμα θα περιέχει τουλάχιστον μια έκφραση της μορφής T buf για κάποιο T και ορισμό του SIZE.

 

Επομένως καλούμαστε τώρα να εξετάσουμε με ποιόν άλλο τρόπο θα μπορούσε να χρησιμοποιηθεί το SIZE ούτως ώστε να δημιουργεί πρόβλημα...

 

Αν πρόκειται να ορίσεις το macro ως integer literal τότε δε μπορώ να φανταστώ καμία τέτοια περίπτωση μιας και ο τύπος των enum values είναι επίσης signed int. Αν ορίσεις το macro ώς κάτι άλλο τότε θα γίνει μετατροπή από αυτό το κάτι άλλο σε int κατά τη δήλωση του πίνακα με απρόβλεπτα αποτελέσματα, κάτι που είναι αυτό ακριβώς που θέλουμε να αποφύγουμε σύμφωνα με το σκεπτικό σου. Επομένως είσαι αναγκασμένος να ορίσεις το macro σαν signed int literal, οπότε έχεις ακριβώς το ίδιο αποτέλεσμα και αν το ορίσεις σε enum.

 

Άρα τελικά παρόλο που ακούγεται αρκετά εκφοβιστικό το ερώτημα που έθεσες τότε to the best of my knowledge θα πρέπει να σου απαντήσω "enum". Είμαι ανοιχτός σε αντιρρήσεις αν μπορούν να στηριχθούν με λογικούς συλλογισμούς.

 

Μα αφού το #define σου παρέχεται δωρεάν και οι περιπτώσεις που καλύπτει είναι περισσότερες και από τις περιπτώσεις που καλύπτει το const και από τις περιπτώσεις που καλύπτει το enum (με άλλα λόγια είναι το πιο ευέλικτο από όλα) :lol:

Με αυτή τη λογική ολόκληρο C++ standards committee είναι (δεν ξέρω τι θέλεις να τους πεις) γιατί έβαλαν στη γλώσσα το static_cast αφού υπάρχει το reinterpret_cast και μάλιστα δυό φορές γιατί έβαλαν και το reinterpret_cast ενώ υπάρχει το C-style cast που τα κάνει όλα και συμφέρει ("πιο ευέλικτο" για να χρησιμοποιήσω δικές σου λέξεις).

 

Νομίζω δε χρειάζεται να γράψω περισσότερα. Αν δε σε προβληματίζει η παραπάνω παράγραφος δε θα σε προβληματίσει οτιδήποτε και να πω.

Δημοσ.

...

Άρα τελικά παρόλο που ακούγεται αρκετά εκφοβιστικό το ερώτημα που έθεσες τότε to the best of my knowledge θα πρέπει να σου απαντήσω "enum". Είμαι ανοιχτός σε αντιρρήσεις αν μπορούν να στηριχθούν με λογικούς συλλογισμούς.

Το enum είναι platform/compiler specific (από char έως int) άρα πάει το portability στην καλύτερη (στη χειρότερη πάει το project).

Δημοσ.

Ενδιαφέρον παράδειγμα. Μιας και μιλάμε αποκλειστικά για fixed size array (το ξεκαθαρίσαμε παραπάνω) σίγουρα το πρόγραμμα θα περιέχει τουλάχιστον μια έκφραση της μορφής T buf για κάποιο T και ορισμό του SIZE.

 

Επομένως καλούμαστε τώρα να εξετάσουμε με ποιόν άλλο τρόπο θα μπορούσε να χρησιμοποιηθεί το SIZE ούτως ώστε να δημιουργεί πρόβλημα...

 

Αν πρόκειται να ορίσεις το macro ως integer literal τότε δε μπορώ να φανταστώ καμία τέτοια περίπτωση μιας και ο τύπος των enum values είναι επίσης signed int. Αν ορίσεις το macro ώς κάτι άλλο τότε θα γίνει μετατροπή από αυτό το κάτι άλλο σε int κατά τη δήλωση του πίνακα με απρόβλεπτα αποτελέσματα, κάτι που είναι αυτό ακριβώς που θέλουμε να αποφύγουμε σύμφωνα με το σκεπτικό σου.

 

Άρα παρόλο που ακούγεται αρκετά εκφοβιστικό το ερώτημα που έθεσες τότε to the best of my knowledge θα πρέπει να σου απαντήσω "enum". Είμαι ανοιχτός σε αντιρρήσεις αν μπορούν να στηριχθούν με λογικούς συλλογισμούς.

 

 

Καλή απάντηση.

 

Όμως, όταν τρέχει ο χρόνος και το date της παράδοσης έρχεται... δεν θέλω να κάτσω να μάθω πώς και τι θα γίνει, εάν γίνει.

 

Επίσης, εάν η μνήμη που έχεις είναι της τάξης μερικών kilo BITS και εάν, εν γένει, είναι αρκετά memory critical το project... νομίζω ότι το #define SIZE 0x01, εάν έχεις 200 γραμμές από #defines, μπορεί να "σώσει" λίγη μνήμη από ένα enum με sizeof = sizeof(int).

Δημοσ.

Το enum είναι platform/compiler specific (από char έως int) άρα πάει το portability στην καλύτερη (στη χειρότερη πάει το project).

Λυπάμαι αλλά έχεις λάθος.

 

6.5.2.2, "Enumeration specifiers":

 

The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.

Αν χρησιμοποιείς κάποιο compiler που δεν είναι conformant στο συγκεκριμένο σημείο (και δε μπορώ να φανταστώ για ποιό λόγο μιας και δεν είναι και κάτι δύσκολο το συγκεκριμένο) αυτό είναι αλλουνού παπά ευαγγέλιο (και βέβαια εκεί κι αν έχει πάει το portability από το παράθυρο).

Επισκέπτης
Αυτό το θέμα είναι πλέον κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...