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

Εγγραφη και αναγνωση binary αρχειων απο C


panoupanou

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

 

 

Παράλογο είναι να λέει κάτι το standard και κάποιος να υποστηρίζει κάτι διαφορετικό, ή το να μη γνωρίζουμε τι ακριβώς λέει το standard αλλά να έχουμε δική μας άποψη. Επιπλέον αυτό που έγραψες αντιφάσκει: "Δεν γνωρίζω να υπάρχει κάτι τέτοιο τεκμηριωμένο..." vs "δείχνει να κάνει μια χαρά conform στα τεκμηριωμένα". Μήπως ήθελες να πεις "γνωρίζω ότι δεν υπάρχει";

 

Δε θα επεκταθώ περισσότερο.

 

Ρε φίλε πλάκα μου κάνεις; Γράφω ξεκάθαρα "(από όσο γνωρίζω)" που αν χρειάζεται να το αναλύσουμε, τότε σημαίνει πως από το 1986 που ξεκίνησα να μαθαίνω C 1η μου φορά ακούω ή/και διαβάζω ότι όταν ορίζεις explicitly μια primitive μεταβλητή στην C πρέπει να είσαι προετοιμασμένος για το ενδεχόμενο ο compiler να της αλλάξει θέση στη μνήμη.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 60
  • Δημ.
  • Τελ. απάντηση

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

Δημοφιλείς Ημέρες

Έψαξα να δω τι λέει το standard γιατί διαφορετικά τζάμπα μιλάμε.

 

(παραλείπω το μέρος όπου φανερά το x στο παραπάνω παράδειγμα έχει automatic storage duration)

 

6.2.4/5:

 

For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

 

Νομίζω δε χρειάζεται να προσθέσω κάτι. It's not a bug, it's a feature.

 

@migf1: "Ρε φίλε" δε σου κάνω πλάκα, απλά μιλάω με τεχνικούς όρους και δε βάζω μέσα στην κουβέντα το τι μου φαίνεται εμένα ή εσένα ή αν πρώτη φορά ακούς για κάτι από το 1821, πράγμα που ποσώς με ενδιαφέρει και δεν είναι επιχείρημα. Να το δοκιμάσεις και συ καμιά φορά, γιατί όπως βλέπεις σίγουρα δεν "μιλάμε καθαρά για bug του compiler".

 

Σχετικό με την όλη φάση (και με πράγματα που πολλοί βλέπουμε καθημερινά γύρω μας): The first rule of programming, περιλαμβάνεται και quote του διάσημου "select isn't broken".

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@defacer:

 

Ναι τους έχω δει τους τεχνικούς όρους με τους οποίους μιλάς, από το νήμα του "support" και του oop... και τα "δικά σου σκεπτικά".

 

Επί του θέματος τώρα, έχεις δίκιο στο προκείμενο διότι παρερμήνευσα αυτό που έγραψες, από δική μου απροσεξία. Νόμιζα πως αναφερόσουν στον iterator του loop.

 

Οπότε ναι, συμφωνώ πως το συγκεκριμένο παράδειγμα είναι bug του κώδικα και όχι του compiler.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@imitheos

 

Πολύ ωραίο, αλλά γιατί είναι bug στον gcc?

 

Σε ANSI C ο κώδικας που κάνει repro δεν κάνει compile, επομένως κάποιος τον έγραψε έχοντας υπόψη ότι μιλάμε για C99 (αυτό το λέω γιατί αν δεν ήταν έτσι τότε πάλι δε θα μιλούσα για bug, θα μιλούσα όμως για εγκληματική αμέλεια όπου προσθέτουμε ένα feature στη γλώσσα και αυτό έχει σαν αποτέλεσμα κώδικας που πριν λειτουργούσε "σωστά" τώρα να λειτουργεί σωστά σύμφωνα με το standard αλλά διαφορετικά απ' ότι πριν).

Ναι δεν είπα ότι είναι ANSI-C ο κώδικας. Φυσικά μιλάμε για C99 ή νεώτερη. Το είπα στην "εισαγωγή" μου κιόλας ότι από την c99 επιτρέπεται να μπλέκουμε δηλώσεις με εκτελέσιμο κώδικα.

 

Σε C99 αν δεν κάνω λάθος (διορθώστε με), κανείς δεν σου εγγυάται ότι το x σε κάθε iteration του loop θα δείχνει στην ίδια μνήμη, επομένως τεχνικά σε κάθε iteration παίρνεις 5 bytes junk. O optimizer βλέπει ότι στα 3 πρώτα iterations δεν κάνεις τίποτα με observable side effects και αποφασίζει να μην τα εκτελέσει καν. Επομένως το μόνο bug που υπάρχει είναι στον κώδικα που βλέπουμε παραπάνω.

 

Σωστά;

Έψαξα να δω τι λέει το standard γιατί διαφορετικά τζάμπα μιλάμε.

 

Νομίζω δε χρειάζεται να προσθέσω κάτι. It's not a bug, it's a feature.

Νομίζω πως στην 6.2.2 αναφέρει αυτό που λες (Each declaration of an identifier with no linkage denotes a unique entity).

 

Εφόσον το πρότυπο αναφέρει τι πρέπει να γίνεται και το παραπάνω δεν εμπίπτει στο πλαίσιο της undefined/unspecified συμπεριφοράς, τότε δεν θα έπρεπε η αλλαγή συμπεριφοράς να είναι documented κάπου ?

 

Edit: Ποιος είμαι ρε μεγάλε, ο τρισμέγιστος. Κατάφερα migf1 και defacer να συμφωνήσουν.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Οπότε, καλά όλα αυτά με τα "τυφλά" writes και reads, αλλά στην πραγματική ζωή απαγορεύεται δια ροπάλου και γενικά θα πρέπει πάντα να κάνεις κάποιο normalization στα δεδομένα που γράφεις για να είσαι σίγουρος πως αυτό που πάει στο αρχείο είναι τελείως ανεξάρτητο από compiler/σύστημα κλπ.

Άλλωστε έχουμε φτάσει στην εποχή του "απόλυτου" αυτόνομου format (json, xml) (καλά όχι τώρα, εδώ και χρόνια) αλλά ακόμα και σε binary καταστάσεις (π.χ. βάσεις δεδομένων) έχουν αυτό που λες, ένα αυτόνομο "binary-data-system" να το πω έτσι.

 

Απλά όπως είπα και πριν είναι πολύ καλό να ξεκινάει κανείς (φοιτητής κ.λ.) απλά και να διαχωρίζει τις έννοιες γράφω binary-data - text.

[ Θυμάμαι την πρώτη φορά που ήρθα σε επαφή με binary αποθήκευση και ανάγνωση (φυσικά έτσι απλά χωρίς normalization) δομών (για άσκηση στις δομές δεδομένων) σε αρχείο. Ήταν για μένα μια αποκάλυψη :shock: - Καλά δεν ήταν και χρόνια πριν :-D ]

 

 

 

@moukoublen:

Μπορείς να δοκιμάσεις το timing και με την clock(), κάπως έτσι....

 

Όντως. Πολύ καλύτερα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ναι δεν είπα ότι είναι ANSI-C ο κώδικας. Φυσικά μιλάμε για C99 ή νεώτερη. Το είπα στην "εισαγωγή" μου κιόλας ότι από την c99 επιτρέπεται να μπλέκουμε δηλώσεις με εκτελέσιμο κώδικα.

 

Ναι, got it. Απλά ήθελα να πω ότι το γεγονός πως το πρόγραμμα συμπεριφέρεται διαφορετικά ανάλογα με το αν έχεις τη δήλωση του x μέσα ή έξω από το loop δεν έχει κάποιο προηγούμενο (μιας και σε ANSI δεν ήταν legal να το έχεις μέσα). Επομένως όποια και αν είναι η τωρινή συμπεριφορά, εφόσον αυτή είναι σύμφωνα με το spec τότε το bug είναι 100% ευθύνη του συγγραφέα του κώδικα μιας και χρησιμοποίησε κάποιο feature με λάθος τρόπο.

 

Το γεγονός ότι σε C και C++ έχουμε τεράστια επιλογή σε λάθος τρόπους είναι θέμα για άλλη κουβέντα. :D

 

Νομίζω πως στην 6.2.2 αναφέρει αυτό που λες (Each declaration of an identifier with no linkage denotes a unique entity).

 

Όχι, αυτό που λες εννοεί πως αν γράψεις δύο φορές int x μέσα σε function (no linkage) τότε αναφέρεσαι σε 2 διαφορετικά x, πράγμα που απαγορεύεται (σε άλλο σημείο) οπότε και δεν κάνει compile. Αν όμως γράψεις δύο φορές static int x σε file scope (internal linkage) τότε απλά "δηλώνεις δύο φορές το ίδιο πράγμα" και δεν υπάρχει πρόβλημα. Βεβαίως αν αντί για να κάνεις declare πας να κάνεις define δύο φορές τότε και πάλι compiler error.

 

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

 

An identifier declared in different scopes or in the same scope more than once can be made to refer to the same object or function by a process called linkage.

 

Ή για να το πω αλλιώς: στο παράδειγμά σου το x γίνεται declared μόνο μία φορά (οπότε και δεν έχει κάτι ενδιαφέρον να μας πει η 6.2.2). Το control flow "περνάει πάνω" από το declaration παραπάνω από μία φορές, αλλά αυτό είναι κάτι διαφορετικό.

 

Οπότε τελικά νομίζω πως συμφωνούμε ότι το σωστό μέρος του spec που περιγράφει την κατάσταση είναι το 6.2.4/5?

 

 

Πολύ θα ήθελα να ήταν διαφορετικά τα πράγματα, αλλά όταν ξεκινήσουμε με διαφωνία το πείραμα έχει δείξει πως το μόνο πράγμα που θα μας κάνει να συμφωνήσουμε είναι το higher authority (ο μπαμπάς, μπορεί να πει κανείς). Sad but true.

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Οπότε τελικά νομίζω πως συμφωνούμε ότι το σωστό μέρος του spec που περιγράφει την κατάσταση είναι το 6.2.4/5?

 

Μα δεν διαφώνησα ποτέ σε αυτό που είπες. Όπως είπες πριν, ο optimizer βλέπει πως δεν χρησιμοποιείς τις τιμές και αφαιρεί τον κώδικα. Εγώ αυτό που ήθελα να θίξω είναι η μη-συνοχή στη συμπεριφορά. Αφενός αλλάξανε τη συμπεριφορά χωρίς να τεκμηριώσουν την αλλαγή (τουλάχιστον προσωπικά πιστεύω ότι δεν είναι καθαρό undefined θέμα ώστε να μη χρειάζεται τεκμηρίωση) και αφετέρου αν προσθέσουμε ένα άσχετο κώδικα μέσα στο βρόχο όπως πχ printf("Hello\n"), τότε ενώ και πάλι δεν χρησιμοποιούμε τις τιμές του x, δεν το αφαιρεί.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μα δεν διαφώνησα ποτέ σε αυτό που είπες. Όπως είπες πριν, ο optimizer βλέπει πως δεν χρησιμοποιείς τις τιμές και αφαιρεί τον κώδικα. Εγώ αυτό που ήθελα να θίξω είναι η μη-συνοχή στη συμπεριφορά. Αφενός αλλάξανε τη συμπεριφορά χωρίς να τεκμηριώσουν την αλλαγή (τουλάχιστον προσωπικά πιστεύω ότι δεν είναι καθαρό undefined θέμα ώστε να μη χρειάζεται τεκμηρίωση) και αφετέρου αν προσθέσουμε ένα άσχετο κώδικα μέσα στο βρόχο όπως πχ printf("Hello\n"), τότε ενώ και πάλι δεν χρησιμοποιούμε τις τιμές του x, δεν το αφαιρεί.

 

Εδώ σε χάνω λίγο. Όταν λες "αλλάξανε τη συμπεριφορά", την αλλάξανε σε σχέση με τι πράγμα; Νωρίτερα που λέγαμε ότι δεν είναι ANSI αλλά C99 αυτό προσπαθούσα να πω, ότι δεν τίθεται θέμα αλλαγής συμπεριφοράς μιας και πριν απλά δεν ήταν legal αυτό. Βοήθα λίγο να καταλάβω please. :)

 

Τώρα όσον αφορά την προσθήκη του printf("Hello"), αυτό προφανώς είναι observable side effect οπότε πρέπει να εκτελεστούν όλα τα iterations του loop. Φαντάζομαι ακόμα κι αν δεν ξέραμε ότι η printf κάνει ορατά πράγματα, μόνο και μόνο το γεγονός πως ο compiler δεν μπορεί να κάνει inline το source της (αφού δεν υπάρχει στο ίδιο translation unit) σημαίνει ότι αναγκάζεται να υποθέσει πως υπάρχουν side effects μιας και δε μπορεί να αποδείξει το αντίθετο.

 

Εδώ θα ήθελα να σχολιάσω και το τι συμβαίνει ακριβώς που σχετίζεται και μ' αυτό που ανέφερε ο migf1 περι μεταφοράς μεταβλητών σε άλλη διεύθυνση μνήμης.

 

Προφανώς και κανένας compiler στα λογικά του δεν υπήρχε περίπτωση να θέλει να κάνει κάτι τέτοιο, και ακόμα περισσότερο νομίζω ότι δε θα μπορούσε κιόλας γιατί κάπου το standard λέει αν θυμάμαι καλά ότι κατά τη διάρκεια του lifetime ενός object, η διεύθυνση μνήμης του παραμένει σταθερή. Εφόσον το lifetime τελειώνει όταν βγούμε για τα καλά από το loop, φανερά καθ 'όλα τα iterations το x παραμένει στην ίδια θέση μνήμης αναγκαστικά και στην πράξη ό,τι αλλαγές γίνουν σε ένα iteration θα είναι ορατές στο επόμενο.

 

Στη θεωρία όμως, το 6.2.4 λέει πως σε κάθε iteration η τιμή του x πρέπει να θεωρείται πως γίνεται reset σε κάτι άγνωστο. Αυτό είναι ένα από τα πολλά μέρη όπου το standard αφήνει unspecified behavior (που είναι διαφορετικό από το undefined behavior) ακριβώς για αυτό το λόγο: για να μπορεί ο compiler να κάνει optimizations.

 

Τεχνικά αυτό που συμβαίνει δεν είναι unspecified behavior κατά τον ορισμό που δίνει γι' αυτήν το standard, οπότε χρησιμοποιώ τον όρο καταχρηστικά -- όμως η ουσία του θέματος είναι η ίδια.

 

Επομένως αυτό που γίνεται στην πράξη είναι πως, ας πούμε αν βάλεις μέσα την printf, o compiler έχει κάθε δίκιο να σου λέει "Κοίτα φίλε, το standard με αφήνει να έχω μέσα στο x ότι μου αρέσει σε κάθε iteration. Αυτό που μου αρέσει λοιπόν είναι να αφήσω ανέγγιχτο ο,τι υπήρχε από το προηγούμενο iteration.".

 

Χωρίς την printf όμως, ο compiler έχει το δικαίωμα να πει "Αυτό που μου αρέσει είναι να μην εκτελέσω καν τα 3 πρώτα iterations γιατί μπορώ να αποδείξω πως δεν θα παίξουν ρόλο. Τι είπες; Θα παίξουν ρόλο γιατί πριν μπορούσες να διαβάσεις αυτά που έγραφες; Λυπάμαι, δε στο υποσχέθηκα ποτέ αυτό και το φταίξιμο που τώρα χάλασε το γλυκό είναι όλο δικό σου".

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

 

 

...

Edit: Ποιος είμαι ρε μεγάλε, ο τρισμέγιστος. Κατάφερα migf1 και defacer να συμφωνήσουν.

 

Γιατί όχι; Δεν έχω πρόβλημα να το παραδεχτώ όταν κάνω λάθος με όποιον και να αντιπαρατίθεμαι (ισχύει αυτό από την μεριά του defacer? μέχρι στιγμής πάντως δεν έχω τέτοια δείγματα στις μεταξύ μας αντιπαραθέσεις)

 

 

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Εδώ σε χάνω λίγο. Όταν λες "αλλάξανε τη συμπεριφορά", την αλλάξανε σε σχέση με τι πράγμα; Νωρίτερα που λέγαμε ότι δεν είναι ANSI αλλά C99 αυτό προσπαθούσα να πω, ότι δεν τίθεται θέμα αλλαγής συμπεριφοράς μιας και πριν απλά δεν ήταν legal αυτό. Βοήθα λίγο να καταλάβω please. :)

Πάντα για C99+ μιλάμε. Όταν λέω αλλάξανε τη συμπεριφορά εννοώ από gcc < 4.7 σε gcc >=4.7.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Πάντα για C99+ μιλάμε. Όταν λέω αλλάξανε τη συμπεριφορά εννοώ από gcc < 4.7 σε gcc >=4.7.

 

Ο 4.7 κάνει ένα optimization που ο μικρότερος δεν έκανε (πρόοδος).

 

Το optimization αυτό έχει σαν αποτέλεσμα κάποιος κώδικας που λειτουργούσε κάνοντας εσφαλμένες υποθέσεις να εμφανίζει τώρα απρόσμενη συμπεριφορά.

 

Δεν έχουν καμία υποχρέωση να σε ενημερώσουν γι' αυτό, όπως και γω δεν έχω καμία υποχρέωση να ενημερώσω το γείτονα που μου κλέβει WiFi ότι έβγαλα τη DSL και έβαλα δορυφορική σύνδεση. Αν του χάλασε το ping λυπάμαι αλλά δεν το είχαμε συμφωνήσει.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το optimization αυτό έχει σαν αποτέλεσμα κάποιος κώδικας που λειτουργούσε κάνοντας εσφαλμένες υποθέσεις να εμφανίζει τώρα απρόσμενη συμπεριφορά.

Δεν έχουν καμία υποχρέωση να σε ενημερώσουν γι' αυτό,

+1000

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

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