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

malloc & free


sonyxp

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

Για την ακρίβεια αυτό που ήταν λάθος ήταν το filename στο σκληρό (διάβαζα το C99+TC2 νομίζοντας πως διάβαζα C90)... :X

Ντροπή :P

 

Αυτά τα έχουμε τακτοποιημένα. Εδώ είχα δώσει links για όσα έγγραφα δίνονται δωρεάν.

 

 

Άρα η ατάκα για το μηδέν δεν αφαιρέθηκε (για την ακρίβεια δε βρίσκω καν το ίδιο κείμενο στο πραγματικό C90) αλλά αντίθετα προστέθηκε κάποια στιγμή μετά την πρώτη κυκλοφορία του C99.

Ήταν προϊόν μιας defect report. Δες το προηγούμενο μήνυμά μου.
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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

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

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

Ντροπή :P

 

Αυτά τα έχουμε τακτοποιημένα. Εδώ είχα δώσει links για όσα έγγραφα δίνονται δωρεάν.

 

 

Ήταν προϊόν μιας defect report. Δες το προηγούμενο μήνυμά μου.

 

"C1990TC2.pdf" -- υποθέτω πως πάνω στο rename κάποια στιγμή αντί για 9 πάτησα 0 and the rest is history... η οποία παρέμεινε θαμμένη γιατί καθε πότε ασχολείται κανείς με C90?  :whistle:

 

Μη μου το τρίβεις άλλο, αισθάνομαι ήδη αρκετά χαζός. :rolleyes:

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

@imitheos:
 
Ακριβώς αυτό που γράφεις δεν θυμόμουν, ότι δηλαδή στην ανάθεση δεικτών το literal 0 συμπεριφέρεται σαν ειδικό keyword της γλώσσας, ταυτόσημο του NULL σε source code context.
 
Δεν το θυμόμουν επειδή την τελευταία φορά που χρειάστηκε να ασχοληθώ με τα internals (πριν πολλά πολλά χρόνια όπως έγραψα και πριν) είχα καταλήξει πως αρκεί να εντυπώσω 2 μόνο πράγματα:
 
α) ότι το NULL δεν είναι πάντα 0-bits (χρήσιμο για την χρήση των calloc()/memset() )
 
β) ότι γράφοντας παντού NULL αντί για 0 δεν θα έχω ποτέ πρόβλημα, ούτε λειτουργικά, ούτε με readability ούτε με checking, είτε μιλάμε για ανάθεση, είτε για σύγκριση, είτε για πέρασμα σε συναρτήσεις, κλπ.
 
Και όντως δεν είχα ποτέ πρόβλημα, δεν δεν με δάγκωσε ποτέ αυτή η πρακτική σε καμία πλατφόρμα από όσες έχω δουλέψει.
 
@defacer:

 

Ε όχι και X για κάτι τόσο θεμελιώδες όσο το bit representation του integer 0 στη C την τελευταία δεκαετία και βάλε (άσε που νομίζω πως το ίδιο ισχύει και για την C++ που θεωρητικά είναι το γήπεδό σου... δεν είμαι σίγουρος όμως για αυτό το τελευταίο). Καραμπινάτος στάνταρ άσος υπέρ του γηπεδούχου migf1 ήταν αυτό το συγκεκριμένο :P

 

Επί της ουσίας τώρα, κοίταξα το ποστ του ημίθεου, κοίταξα και αυτά που έχω γράψει περί object, κοίταξα στα γρήγορα και το πρότυπο. Εξακολουθώ να μην καταλαβαίνω που και γιατί αντιφάσκω.
 
Το απόσπασμα που παραθέτει ο ημίθεος υπάρχει στο πρότυπο, υπάρχουν όμως και δεκάδες άλλα όπως για παράδειγμα...
 

6.3.2.1 Lvalues, arrays, and function designators

1 An lvalue is an expression (with an object type other than void) that potentially
designates an object;
[64] if an lvalue does not designate an object when it is evaluated, the
behavior is undefined. When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, does not have a constqualified
type, and if it is a structure or union, does not have any member (including,
recursively, any member or element of all contained aggregates or unions) with a constqualified
type.

 

[64] The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2, in which the left
operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an
object ‘‘locator value’’. What is sometimes called ‘‘rvalue’’ is in this International Standard described
as the ‘‘value of an expression’’.
An obvious example of an lvalue is an identifier of an object. As a further example, if E is a unary
expression that is a pointer to an object, *E is an lvalue that designates the object to which E points
.

 

...

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object
and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
...
 
6.3.2.3 Pointers
 
1 A pointer to void may be converted to or from a pointer to any object type. A pointer to
any object type may be converted to a pointer to void and back again
; the result shall
compare equal to the original pointer.
...
 
6.2.5 Types
...
20.
...
— A pointer type may be derived from a function type, an object type, or an incomplete
type, called the referenced type. A pointer type describes an object whose value
provides a reference to an entity of the referenced type
. A pointer type derived from
the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a
pointer type from a referenced type is called ‘‘pointer type derivation’’.
...

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

 

 


Από την στιγμή λοιπόν που το κάνεις cast, ουσιαστικά το παίρνεις πάνω σου και λες του compiler να κάνει treat το 0xabad1dea ως διεύθυνση ενός object of type void (ή όποιον άλλον τύπο έχεις ορίσει για το p2).

 

Σε ότι αφορά τώρα το τι γίνεται σε non-0bits implementations του NULL με το παράδειγμα που δώσαμε και οι 3 μας (αρχικά ο ημίθεος, μετά εγώ και μετά εσύ.. αυτό με το cast από int 0), η απάντηση πρέπει να βρίσκεται κάπου μέσα στις 8 παραγράφους της ενότητας 6.3.2.3 Pointers του προτύπου, ενδεχομένως σε συνδυασμό με τα forward references που αναφέρει στο τέλος της, αλλά frankly δεν έχω το κουράγιο να κάτσω να τα .. αποκρυπτογραφήσω αυτή τη στιγμή.

 

 

 

ΥΓ. Δεν εξέλαβα πως το θέμα με το bit-representation του 0 στα integer types το παρέλειψες σκόπιμα από την παράθεση που έκανες αρχικά. Δεν σου καταλόγισα δηλαδή δόλο (ούτε δημόσια ούτε από μέσα μου).

 

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

 

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

όταν πείθεσαι, είτε για να το παραδεχτείς πρέπει να μου βγάλεις το λάδι αναγκάζοντάς με να γράφω σεντόνια στο φόρουμ ή να διαβάζω σεντόνια από πρότυπα, σημειώσεις πανεπιστημίων, κλπ για να σε πείσω, είτε και τα 2 μαζί :P

 

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

 

 

 


 

...

Μήπως να το γυρίζαμε πλέον στο C11?

 

 

Δεν νομίζω πως είναι καλή ιδέα. Εδώ συχνά χάνουμε την μπάλα και με το C99 ακόμα κι όσοι την έχουμε φάει με το κουτάλι (και την C90) φαντάσου τι έχει να γίνει αν πάμε σε C11.

 

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

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

β) ότι γράφοντας παντού NULL αντί για 0 δεν θα έχω ποτέ πρόβλημα, ούτε λειτουργικά, ούτε με readability ούτε με checking, είτε μιλάμε για ανάθεση, είτε για σύγκριση, είτε για πέρασμα σε συναρτήσεις, κλπ.

 

Και όντως δεν είχα ποτέ πρόβλημα, δεν δεν με δάγκωσε ποτέ αυτή η πρακτική σε καμία πλατφόρμα από όσες έχω δουλέψει.

 

Ε αφού γράφοντας NULL στην ουσία γράφεις 0 λόγω του macro... το ίδιο είναι (σε pointer context τουλάχιστον).

 

 

Ε όχι και X για κάτι τόσο θεμελιώδες όσο το bit representation του integer 0 στη C την τελευταία δεκαετία και βάλε (άσε που νομίζω πως το ίδιο ισχύει και για την C++ που θεωρητικά είναι το γήπεδό σου... δεν είμαι σίγουρος όμως για αυτό το τελευταίο). Καραμπινάτος στάνταρ άσος υπέρ του γηπεδούχου migf1 ήταν αυτό το συγκεκριμένο :P

 

 

Υπάρχει βέβαια μια σημαντική διαφορά ανάμεσα στο αν αυτό το bit representation είναι ορισμένο από το πρότυπο ή implementation-defined. Προσωπικά δε μου χρειάστηκε ποτέ να ξέρω για πρακτικούς λόγους αν το all zero bits == 0 είναι ορισμένο από το πρότυπο. Έτσι κι αλλιώς όποτε χρειάζομαι κάτι τόσο low-level και άρα "επίφοβο" βάζω πάντα σχετικά compile-time assertions (C, C++, με την ευκαιρία να πω ότι η manual υλοποίηση compile-time assertions την οποία έμαθα από τον Alexandrescu είναι εξαιρετικά διδακτική γιατί βασίζεται στο interaction πολλαπλών "ασυνήθιστων" language features ταυτόχρονα) και μετά απλά το ξεχνάω. Αν υπάρχει ποτέ πρόβλημα, θα με ειδοποιήσει ο compiler. Σε όποιες περιπτώσεις δε μπορεί να χρησιμοποιηθεί τέτοιο assertion τότε απλά unit test.

 

Αυτά τα παραπάνω ισχύουν τόσο για C όσο και για C++ (η οποία κάποτε ήταν το γήπεδό μου όπως λες αλλά πλέον είναι κάτι του στυλ #4 στην κατάταξη).

 

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

 

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

 

 

 

Για να πω την αλήθεια θα προτιμούσα να μη χρειαζόταν καν να ανοίξω το πρότυπο για να δω αν τα είπες σωστά ή όχι σχετικά με το representation, αλλά αυτό είναι άλλη κουβέντα.

 

 

 

Και τώρα που τα είπαμε αυτά, ξεκινάει η πλάκα... μιας και αυτή τη στιγμή δεν έχω το C11, βρήκα αυτή την όμορφη σχετική ερώτηση στο SO η οποία πολύ βολικά μιλάει για C99, C11 και επίσης για C++. Αφήνοντας απέξω την C99, το αστείο είναι πως σε C11 και C++ από το κείμενο του προτύπου technically δεν προκύπτει τέτοια εγγύηση, γιατί πάντα αφήνει παραθυράκια. Το μόνο πράγμα που "κλειδώνει" το τι αντιπροσωπεύουν τα all zero bits είναι η πρόταση που ανέφερες στο C99.

 

Επομένως (και σίγουρα θα υπάρξουν διαφωνίες εδώ), παρόλο που πλέον το gut feeling μου λέει ότι all zero bits == 0 (βασικά επειδή το έλεγε στη C99TC2), τόσο το κείμενο των νεώτερων προτύπων όσο και το consensus στο SO (όπου βέβαια στην κουβέντα συμμετέχουν "όχι τυχαίοι" χρήστες) φαίνεται να λέει πως δεν υπάρχει τέτοια εγγύηση.

 

Προσοχή: πρωτού σχηματίσετε γνώμη διαβάστε όλες τις απαντήσεις και τα σχόλια προσεκτικά. Είναι κάπως τεχνικό read.

 

 

Επί της ουσίας τώρα, κοίταξα το ποστ του ημίθεου, κοίταξα και αυτά που έχω γράψει περί object, κοίταξα στα γρήγορα και το πρότυπο. Εξακολουθώ να μην καταλαβαίνω που και γιατί αντιφάσκω.

 

Νωρίτερα είπες αυτό:

 

Από την στιγμή λοιπόν που το κάνεις cast, ουσιαστικά το παίρνεις πάνω σου και λες του compiler να κάνει treat το 0xabad1dea ως διεύθυνση ενός object of type void (ή όποιον άλλον τύπο έχεις ορίσει για το p2).

 

Αυτό σίγουρα δεν ισχύει (η έκφραση βασικά είναι τεχνικά λάθος), και όλα τα υπόλοιπα απορρέουν από εδώ. Δεν ξέρω από πού να το πιάσω διαφορετικά, οπότε να πω απλά ότι το αν η Χ είναι διεύθυνση ενός object (το οποίο βέβαια δε μπορεί να έχει type void άσχετα αν ο pointer που δείχνει εκεί είναι void*) είναι στην ουσία ένα "χαρακτηριστικό του σύμπαντος": είτε ισχύει, είτε δεν ισχύει. Δεν είναι στο χέρι σου να αλλάξεις αυτή την κατάσταση δημιουργώντας pointers. Σε κάποιες περιπτώσεις μπορείς να την αλλάξεις κάνοντας malloc ή free, αλλά και πάλι όχι σε όλες (π.χ. objects με σε static storage duration).

 

Αν αυτό που κάνω quote είναι αλήθεια, τότε κάποια πράγματα που αναφέρονται στο standard δεν μπορούν να ισχύουν ταυτόχρονα (το quote του ημίθεου). Και βέβαια εννοείται πως your word vs the standard == the standard wins, αλλά όταν λέω αντιφάσκεις εννοώ πως έχεις δώσει και συ ο ίδιος παράδειγμα του οποίου η καταγεγραμμένη συμπεριφορά είναι διαφορετική απ' αυτό που προκύπτει από το παραπάνω quote.

 

Δηλαδή αν αυτό ήταν ένας pointer σε object:

 

int i = 0;
void* p = (void*)i;
 

τότε το p == NULL θα έπρεπε να είναι false σε οποιοδήποτε implementation, αλλά δεν είναι. Επομένως ή το implementation δεν είναι σωστό, ή δεν ισχύει η παράθεση.

 

 

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

 

Δεν έχω κανένα θέμα στο να παραδεχτώ ότι γνωρίζεις πολύ περισσότερα -- τουλάχιστον στη C, γιατί για άλλα θέματα δεν έχω πολλά δείγματα γραφής. Το θέμα είναι πως έχω καταλήξει στο ότι έχουμε διαφορετικό ορισμό του "γνωρίζω": για μένα "γνωρίζω" σε προτυποθέματα σημαίνει το έχω διαβάσει με τα μάτια μου και αν με ρωτήσεις ξέρω να σου πώ πού αναφέρεται (ίσως όχι τον αριθμό της παραγράφου απέξω αλλά περιγραφικά). Για σένα "γνωρίζω" καταλαβαίνω πως σημαίνει κάτι διαφορετικό, το οποίο αφήνει ανοιχτό το ενδεχόμενο να μην είναι έτσι τα πράγματα (και όντως κάποιες φορές δεν είναι).

 

Νομίζω αυτό είναι φανερό και από την έκφραση που χρησιμοποίησες "χωρίς να χρειάζεται να καταφεύγω στα πρότυπα". Το βρίσκω παντελώς αδιάφορο στα πλαίσια τέτοιων συζητήσεων το αν χρειάζεται να καταφεύγει κανείς στα πρότυπα κάθε φορά. Το θέμα είναι πως αν δεν έχεις καταφύγει στα πρότυπα τουλάχιστον μία φορά για κάποιο θέμα (και στην πράξη βέβαια μόνο μία δε φτάνει) τότε με το δικό μου ορισμό δεν είσαι σε θέση να πεις ότι "γνωρίζεις". Είμαι σίγουρος (τον βάφω μπλε και τον πετάω στη θάλασσα) ότι υπάρχουν θέματα στα οποία παρόλο που έχεις πολύ περισσότερη εμπειρία από μένα και τον ημίθεο μαζί, εντούτοις αν μας καλούσαν να δώσουμε μια definitive απάντηση η δική σου θα ήταν η λιγότερο ικανοποιητική ακριβώς επειδή "τα γνωρίζεις και δε χρειάζεται να καταφύγεις στο πρότυπο". Και αυτή η προσέγγιση είναι που με κάνει να θέλω να καταφύγω στο πρότυπο πολλές φορές όταν αναφέρεις κάτι: δεν έχω εμπιστοσύνη ότι το έκανες νωρίτερα εσύ.

 

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

 

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

 

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

όταν πείθεσαι, είτε για να το παραδεχτείς πρέπει να μου βγάλεις το λάδι αναγκάζοντάς με να γράφω σεντόνια στο φόρουμ ή να διαβάζω σεντόνια από πρότυπα, σημειώσεις πανεπιστημίων, κλπ για να σε πείσω, είτε και τα 2 μαζί :P

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

 

 

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

Καταρχήν μη μπερδεύεις τις θέσεις μου γενικά με τις θέσεις μου επι θεμάτων όπου υπάρχει ο υπέρτατος κριτής (το πρότυπο) όπως είναι η C.

 

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

 

Τέλος όσον αφορά τα περι τοποθετήσεων at the very least θα μπορούσα και γω να πω τα ίδια, οπότε ας το αφήσουμε εδώ μιας και η ανθρωπότητα είπαμε δεν είναι ακόμα έτοιμη.

 

 

Δεν νομίζω πως είναι καλή ιδέα. Εδώ συχνά χάνουμε την μπάλα και με το C99 ακόμα κι όσοι την έχουμε φάει με το κουτάλι (και την C90) φαντάσου τι έχει να γίνει αν πάμε σε C11.

 

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

Δεν είναι στο χέρι μας. Adapt or die.

 

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

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

β) ότι γράφοντας παντού NULL αντί για 0 δεν θα έχω ποτέ πρόβλημα, ούτε λειτουργικά, ούτε με readability ούτε με checking, είτε μιλάμε για ανάθεση, είτε για σύγκριση, είτε για πέρασμα σε συναρτήσεις, κλπ.

 

Και όντως δεν είχα ποτέ πρόβλημα, δεν δεν με δάγκωσε ποτέ αυτή η πρακτική σε καμία πλατφόρμα από όσες έχω δουλέψει.

#include <stdio.h>
#include <unistd.h>

#define CNULL (void *)0   // C
#define CPPNULL   0       // C++
int main(void)
{

	printf("C NULL\n");
	execl("/bin/sh", "sh", "-c", "date", CNULL);
	printf("C++ NULL\n");
	execl("/bin/sh", "sh", "-c", "date", CPPNULL);

	return 0;
}
Χαζό παράδειγμα φυσικά αλλά βαριόμουν να ανοίξω Virtualbox και να τρέξω το Visual Studio οπότε πήρα αυτούσιο τον κώδικα του execl από το c-faq.

    gcc -Wall -x c - 
<stdin>: In function ‘main’:
<stdin>:12:2: προειδοποίηση: missing sentinel in function call [-Wformat=]
Όπως είπαμε ήδη πολλές φορές, αν έχουμε C++ compiler, το NULL κάνει κακό αντί για καλό. Βέβαια οι exec συναρτήσεις δεν είναι και οι καλύτερες από πλευρά συμπεριφοράς ούτε και χρησιμοποιούνται τόσο συχνά από νέους αλλά δεν παύει να αποδεικνύει το point. Στη πλειοψηφία των περιπτώσεων όμως NULL και 0 είναι ταυτόσημα.

 

 

Υπάρχει βέβαια μια σημαντική διαφορά ανάμεσα στο αν αυτό το bit representation είναι ορισμένο από το πρότυπο ή implementation-defined. Προσωπικά δε μου χρειάστηκε ποτέ να ξέρω για πρακτικούς λόγους αν το all zero bits == 0 είναι ορισμένο από το πρότυπο.

 

Αφήνοντας απέξω την C99, το αστείο είναι πως σε C11 και C++ από το κείμενο του προτύπου technically δεν προκύπτει τέτοια εγγύηση, γιατί πάντα αφήνει παραθυράκια. Το μόνο πράγμα που "κλειδώνει" το τι αντιπροσωπεύουν τα all zero bits είναι η πρόταση που ανέφερες στο C99.

 

Επομένως (και σίγουρα θα υπάρξουν διαφωνίες εδώ), παρόλο που πλέον το gut feeling μου λέει ότι all zero bits == 0 (βασικά επειδή το έλεγε στη C99TC2), τόσο το κείμενο των νεώτερων προτύπων όσο και το consensus στο SO (όπου βέβαια στην κουβέντα συμμετέχουν "όχι τυχαίοι" χρήστες) φαίνεται να λέει πως δεν υπάρχει τέτοια εγγύηση.

Δεν διάβασα όλη την ερώτηση αλλά με μια γρήγορη ματιά που έριξα, λένε πως η σύνταξη του C++11 είναι λίγο ασαφής ενώ το C11 είναι "explicit". Στο n1570 έγγραφο που έχω, το κείμενο του C11 στη συγκεκριμένη παράγραφο είναι ίδιο με αυτό του C99-TC2/3. Φυσικά μιλάμε πως μόνο το all-bits-zero είναι εγγυημένο. Όλα τα άλλα patterns μπορεί να έχουν οποιαδήποτε συμπεριφορά στα padding/parity bits. Το πρότυπο αφήνει επίτηδες πολλά πράγματα χωρίς εξήγηση :(

 

Γενικά όσοι δουλεύουμε C μας έχει καλομάθει η x86. Έπρεπε ο κάθε προγραμματιστής να μαθαίνει πρώτα σε κανένα alpha, sparc, mips, whatever και μετά να πηγαίνει σε x86 :P. Ή κανένα cray σαν εκείνο για το οποίο μιλούσαμε στο άλλο νήμα που οι δείκτες έχουν padding bits και άλλο μέγεθος για κάθε τύπο :)

 

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

 

Χαζό παράδειγμα follows:

#include <stdio.h>

int main(void)
{

	#ifdef SPARCSIM
	__asm__(
		"pushf\n"
		"orl $(1<<18), (%esp)\n"
		"popf\n"
	);
	#endif

	char myarr[8] = { 6, 9, 2, 7, 1, 5, 3, 4};
	char *p1;
	int *p2;

	p1 = myarr;
	p1++;
	p2 = (int *)p1;

	printf("myarr bytes 1 - 3 = %08x\n",*p2);

	return 0;
}
% gcc -Wall -m32 -o x86 oo.c
% gcc -Wall -m32 -o sparc -DSPARCSIM oo.c
% ./x86 
myarr bytes 1 - 3 = 01070209
% ./sparc 
zsh: bus error  ./sparc
Όπως βλέπουμε, υπό κανονικές συνθήκες σε x86 παίρνουμε 01070209 οπότε λόγω little-endian έχουμε με τη σειρά τα bytes 9,2,7,1 δηλαδή τα στοιχεία της array ξεκινώντας από το δεύτερο. Αν όμως ενεργοποιήσουμε το 18ο bit του καταχωρητή σημαιών ώστε να μην επιτρέπει unaligned προσπέλαση για να μιμηθούμε άλλες αρχιτεκτονικές (για την ακρίβεια έγραψα μεν εξομοίωση sparc αλλά δεν θυμάμαι αν το sparc απαγορεύει unaligned προσπέλαση :P), τότε παίρνουμε το πρόγραμμα στο χέρι.
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν διάβασα όλη την ερώτηση αλλά με μια γρήγορη ματιά που έριξα, λένε πως η σύνταξη του C++11 είναι λίγο ασαφής ενώ το C11 είναι "explicit". Στο n1570 έγγραφο που έχω, το κείμενο του C11 στη συγκεκριμένη παράγραφο είναι ίδιο με αυτό του C99-TC2/3. Φυσικά μιλάμε πως μόνο το all-bits-zero είναι εγγυημένο. Όλα τα άλλα patterns μπορεί να έχουν οποιαδήποτε συμπεριφορά στα padding/parity bits. Το πρότυπο αφήνει επίτηδες πολλά πράγματα χωρίς εξήγηση :(

Explicit, αλλά explicit όσον αφορά τι ακριβώς είναι το θέμα...

 

- Ο accepted answer φαίνεται σε πρώτη φάση να λέει πως ναι είναι guaranteed αλλά μετά ότι θεωρεί πως δεν υπάρχει guarantee.

- Και τα 2 standards μιλάνε για "pure binary representation", αλλά δεν το εξηγούν περισσότερο. Η c++ έχει ένα footnote όπου περιγράφει το προφανές, αλλά τα footnotes είναι informative και όχι normative.

- Επιπλέον Ο DeadMG σωστά λέει πως πουθενά δεν απαγορεύεται ρητά το να έχεις bias στην αναπαράσταση (δηλαδή να πεις π.χ. 0x00 = 144, 0x01 = 145, κλπ), κάτι που θα μπορούσε να γίνεται ενώ ισχύει το "pure binary".

- Yπάρχει μια deleted answer (υπάρχει 10K reputation threshold για να μπορεί κανείς να τη δει) όπου μιλάνε περισσότερο για C++, στην οποία αναφέρεται πως

 

 

C++ has always been less explicit than C about how integers are represented. It has never been clear to me whether this is because:

  • the C++ authors don't think that stuff needs spelling out, that it's implied by "pure binary notation", and the text in C is redundant. In which case C++11 does guarantee what you want.
  • the C++ authors want to allow more flexibility to implementations to invent new meanings for the sign bit, and (perhaps) other non-value bits. In which case the stuff about "pure binary notation" would be read as referring only to the value-and-sign bits, and you don't have the guarantee you want.

I suspect the former may have been in the minds of some or all of the authors -- the fact that they don't even bother defining the term except in a footnote suggest to me that they think this stuff is all obvious. But I'm not certain that a reasonable reader is obliged to interpret the language that way...

 

 

- Από την άλλη σκέφτεται κανείς: είναι δυνατόν στη C99 να υπήρχε το guarantee και μετά να το έβγαλαν;

- Από την πιο άλλη, στο defect report που οδήγησε στην προσθήκη της επίμαχης πρότασης στο C99 TC2 φαίνεται ξεκάθαρα πως η αιτιολόγηση για να μπει ήταν πως "όλος ο κόσμος το κάνει και περιμένει να δουλέψει, ας το βάλουμε μέσα". Το οποίο σημαίνει ξεκάθαρα πως πριν το 2004 που κυκλοφόρησε το TC2 αυτή η συμπεριφορά δεν ήταν standard, και πως δεν υπήρχε κάποιος "ιδιαίτερος λόγος" πέραν του ότι ο κόσμος το έκανε ευρέως (χωρίς να είναι guaranteed!) ήδη απο νωρίτερα.

 

What a mess...

 

 

 

migf1, αυτό είναι καλό παράδειγμα να δώσω μαζί με τα σχόλιά μου παραπάνω: λες νωρίτερα "την τελευταία δεκαετία και βάλε" -- δε θα κάτσω να ψειρίσω να πω ότι όχι δεν είναι 10 χρόνια είναι 9 και δεν έχει βάλε, ούτε να ρωτήσω από πότε πιστεύεις πως ισχύει το all zero bits == 0 -- απλά, τέτοιες μη-τεκμηριωμένες δηλώσεις από κάποιον που δε συνηθίζει να κάνει quote το standard μου προκαλούν ανησυχία.

 

 

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

Καλησπέρα στην ομήγυρη,

 

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

 

@imitheos:

 

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

 

Για C όμως μπορώ, βασιζόμενος στην πολύ μεγαλύτερη εμπειρία μου με αυτή τη γλώσσα. Πιστεύω πως η πρακτική που έχω "προπαγανδίσει" (sic) σε αυτό το νήμα περί NULL, 0-bits, κλπ, αν αποφασίσει κανείς να την ακολουθήσει έστω και χωρίς να το ψάξει και μόνος του δεν πρόκειται να τον ζημιώσει συγκριτικά με το literal 0, συν ότι at the very least θα γράφει και πιο readable κώδικα. Επίσης απελευθερώνει το μυαλό του από το να θυμάται αυτή την ειδική περίπτωση (αυτό δηλαδή που συνέβη και σε μένα, μόνο που εγώ όταν το χρειάστηκα για 1η φορά το έψαξα μόνος μου, έβγαλα και κράτησα το συμπέρασμα που κατέθεσα κι εδώ κι από τότε το χρησιμοποιώ χωρίς πρόβλημα).

 

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

 

Επίσης, προσωπικά αποφεύγω (και δεν έχω προτρέψει και κανέναν) να ορίζω δικό μου definition για το NULL, θεωρώντας πως οι devs του compiler στην εκάστοτε πλατφόρμα ξέρουν καλύτερα από μένα το πως να ορίζουν το NULL και γιατί (βέβαια έχω δει κι εγώ την τάση να ορίζουν οι programmers μόνοι τους τα NULL αλλά δεν το έχω υιοθετήσει).

 

Στα υπόλοιπα που γράφεις συμφωνώ κι εγώ, και ήμουν από τους τυχερούς/άτυχους που έμαθαν προγραμματισμό σε mainframes, μιας και τότε όχι μόνο δεν υπήρχαν καν pc, αλλά υπήρχαν μόνο mainframes και motorolla 68000 micro-computers (macintosh, atari st, amiga, κλπ... κι αυτά στα πρώτα τους βήματα). Έχουν περάσει πολλά χρόνια από την τελευταία φορά που χρειάστηκε να προγραμματίσω σε "εξωτικές" πλατφόρμες, οπότε είναι αναμενόμενο να μη θυμάμαι λεπτομέρειες, αλλά γενικά συμπεράσματα που είχα εντυπώσει στο μυαλό μου από τότε τα θυμάμαι (άλλα με περισσότερες λεπτομέρειες, άλλα με λιγότερες, άλλα με καθόλου λεπτομέρειες).

 

Χάριν πληρότητας όμως, να προσθέσω πως το πρότυπο (τουλάχιστον από C99 και μετά, δεν θυμάμαι τι γινόταν παλαιότερα) ορίζει πως στην ακρίβεια και στο εύρος των ακεραίων ΔΕΝ συμπεριλαμβάνονται τυχόν padding bits. Καθώς και πως τυχόν αριθμητικές πράξεις με τιμές ακεραίων μπορούν να χρησιμοποιήσουν padding bits μονάχα για exceptions (π.χ. range overflow) ή για traps.

 

Με λίγα λόγια, τα padding bits δεν συμπεριλαμβάνονται στα valid values. Αφήνω ανοιχτό ένα μικρό ενδεχόμενο να το θυμάμαι λάθος, οπότε διασταυρώστε το και μόνοι σας όσοι ενδιαφέρεστε και διορθώστε αν το θυμάμαι λάθος, γιατί πραγματικά δεν μου αρέσει να παίρνω στο λαιμό μου κόσμο (απλώς μόλις μπήκα σπίτι κουρασμένος και ειλικρινά βαριέμαι να ψάχνω τώρα τα πρότυπα).

 

@defacer:

 

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

 

Σχετικά με το C11, η άποψη μου είναι πως δεν αποτελεί προτεραιότητα να ασχολιόμαστε με ένα πρότυπο για το οποίο υπάρχει μηδενικό code-base, παραμερίζοντας τα πρότυπα στα οποία είναι γραμμένο το 99.99% του code-base. Επίσης, στο δικό μου αντίγραφο της C11 αναγράφεται ότι ακριβώς και στο C99 σχετικά με το all zero bits representation των integer 0.

 

Σχετικά τώρα με την σημασία του 0-bits representation στην κουβέντα, αποτελεί νομίζω την βασική αιτιολόγηση του γιατί δουλεύει το παράδειγμα που πρωτο-έδωσε ο ημίθεος και αναρωτήθηκε γιατί δουλεύει σε x86. Αποτελεί επίσης βασική αρχή πάνω στην οποία πατάει το 0-bits implementation των null-pointers σε συνδυασμό με τις calloc()/memset().

 

Αναφορικά με το object, να στο πω αλλιώς. Αν o δείκτης δεν γινόταν treat ως διεύθυνση ενός object (ή αν προτιμάς ως ανφορά ενός object... created ή όχι δεν έχει σημασία, initialized ή όχι πάλι δεν έχει σημασία), τότε πως το εξηγείς το ότι ο παρακάτω κώδικας δουλεύει as expected σε όλους τους comilers σε πλήρη αρμονία με το μέγεθος του εκάστοτε object type (ελπίζω να μη μου... επιχειρηματολογήσεις με void * :P)?

 

#include <stdio.h>

int main( void )
{
	int *p;

	printf( "%x ", (long unsigned) p );
	p++;
	printf( "%x\n", (long unsigned)p );

	return 0;
}
άλλαξε το int σε ότι θέλεις (πλην void).

 

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

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

Δηλαδη τωρα ολα αυτα τα πανια ειναι για το θεμα αν το NULL == 0 ;

Κουβέντα για το TIPOTA (NULL)  :-D

Χεχε. Τώρα θα μας μάθετε ? Καλά κάνετε πάντως και πατάτε μια φωνή όταν ξεφεύγουμε :)

 

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

Μα δεν μιλούσα για την γλώσσα c++ ούτε εννοούσα να γράφεις c++ με σύνταξη c. Το ανέφερα σαν αντεπιχείρημα σε αυτό που είπες ότι με το NULL δεν έπεσες ποτέ σε παγίδες. Το point μου ήταν ότι ένας νέος χρήστης μπορεί να γράφει C χωρίς να ξέρει ότι το περιβάλλον του (πχ Visual Studio) παρέχει στην πραγματικότητα C++ compiler και óxi C compiler οπότε μπορεί κάλλιστα να πέσει σε παγίδα (υπό ψιλο-απίθανες συνθήκες το δέχομαι).

 

Όπως και να χει, σταματάω εδώ για να μη το συνεχίζουμε και ενοχλούμε τους υπολοίπους.

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

Σχετικά με το C11, η άποψη μου είναι πως δεν αποτελεί προτεραιότητα να ασχολιόμαστε με ένα πρότυπο για το οποίο υπάρχει μηδενικό code-base, παραμερίζοντας τα πρότυπα στα οποία είναι γραμμένο το 99.99% του code-base. Επίσης, στο δικό μου αντίγραφο της C11 αναγράφεται ότι ακριβώς και στο C99 σχετικά με το all zero bits representation των integer 0.

 

Δεν ξέρω αν η C είναι κάποιο ιδιαίτερο φρούτο, αλλά κάνοντας τον παραλληλισμό με C++ θα διαφωνήσω σχετικά με την προτεραιότητα. Πολύ συνοπτικά: σε 1,2,3,Ν τέλος πάντων χρόνια όταν λέμε "C++" θα εννοούμε "C++11" (για τη C++ ήδη έχει γίνει αυτό, απλά το λέω πιο γενικά), κι αυτό είναι γνωστό από τώρα. Επομένως κάθε στιγμή που επιλέγεις ελεύθερα να ασχολείσαι με προηγούμενο πρότυπο σε βάρος του καινούριου είναι για μένα χαμένος χρόνος. Εδώ σηκώνει βέβαια συζήτηση αλλά μέσες άκρες νομίζω κατάλαβες το σκεπτικό.

 

Για το representation του 0 σε C11 μου κάνει εντύπωση που δεν το ανέφερε κανείς σε κείνη την ερώτηση παρόλο που έχουν παραθέσει άλλα quotes από C11. Αλλά δεν έχω το πρότυπο οπότε αρκούμαι σ' αυτά που ακούω από δεύτερο χέρι.

 

Αναφορικά με το object, να στο πω αλλιώς. Αν o δείκτης δεν γινόταν treat ως διεύθυνση ενός object (ή αν προτιμάς ως ανφορά ενός object... created ή όχι δεν έχει σημασία, initialized ή όχι πάλι δεν έχει σημασία), τότε πως το εξηγείς το ότι ο παρακάτω κώδικας δουλεύει as expected σε όλους τους comilers σε πλήρη αρμονία με το μέγεθος του εκάστοτε object type (ελπίζω να μη μου... επιχειρηματολογήσεις με void * :P)?

 

Ο δείκτης p είναι από μόνος του object (6.2.5/20) και έχει συγκεκριμένο τύπο. Για το pointer arithmetic κάνω quote το 6.5.6/2:

 

 

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type and the other shall have integer type.

 

 

 

 

Είμαι σίγουρος πως καταλαβαίνεις τη διαφορά ανάμεσα στο "a pointer to an object type" και στην ίδια έκφραση χωρίς τη λέξη type μέσα.

 

Επιπλέον ξαναλέω πως τρέχοντας το ίδιο example που δίνεις στο ideone έτυχε να τυπώσει 0 4. Προφανώς αν πριν την πρόσθεση συγκρίνω με NULL θα δώσει true. Αλλά όπως έχω βαρεθεί να κάνω quote το quote του ημίθεου, είναι δεδομένο πως pointer to object  (χωρίς type εδώ) και null pointer επιβάλλεται να κάνουν compare unequal. Άρα ο p δεν μπορεί να είναι pointer to object. Είναι σκέτο pointer στην καθομιλουμένη, ή object of type pointer to integer σε standardese.

 

Τέλος, η 6.5.3.2/4 λέει σχετικά με τον indirection operator *:

 

 

The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

 

Είναι φανερό ότι το invalid value και το "points to an object" είναι αμοιβαία αποκλειόμενες περιπτώσεις. Σου γυρνάω λοιπόν την ερώτηση σχετικά με το παράδειγμα που έφερες και ρωτάω με τη σειρά μου: εφόσον υποστηρίζεις ότι όντως it points to an object χωρίς να έχεις κάνει initialize τον pointer, τότε (α) γιατί αν γράψω *p = 42 θα κρασάρουμε και (β) ποιά θα ήταν η (διαφορετική) περίπτωση που έχει invalid value?

 

 

Αν ακόμα δεν πείθεσαι take a step back και θα ίσως δεις ότι έτσι που το θέτω έχει λογική. Αν πάλι όχι, δε νομίζω πως έχει νόημα να ξαναλέμε τα ίδια και τα ίδια. Feel free να ρωτήσεις στο SO και να ποστάρεις το link.

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

Δεν ξέρω αν η C είναι κάποιο ιδιαίτερο φρούτο, αλλά κάνοντας τον παραλληλισμό με C++ θα διαφωνήσω σχετικά με την προτεραιότητα. Πολύ συνοπτικά: σε 1,2,3,Ν τέλος πάντων χρόνια όταν λέμε "C++" θα εννοούμε "C++11" (για τη C++ ήδη έχει γίνει αυτό, απλά το λέω πιο γενικά), κι αυτό είναι γνωστό από τώρα. Επομένως κάθε στιγμή που επιλέγεις ελεύθερα να ασχολείσαι με προηγούμενο πρότυπο σε βάρος του καινούριου είναι για μένα χαμένος χρόνος. Εδώ σηκώνει βέβαια συζήτηση αλλά μέσες άκρες νομίζω κατάλαβες το σκεπτικό.

Το προηγούμενο πρότυπο είναι χαμένος χρόνος όταν το ενδιαφέρον σου είναι ακαδημαϊκό. Όταν ασχολείσαι επαγγελματικά, τότε πρώτη προτεραιότητα έχει το υπάρχον code base και τα διαθέσιμα εργαλεία. Επαγγελματικά χαμένος χρόνος είναι να βιάζεσαι να χρησιμοποιήσεις ένα πρότυπο που δεν το υποστηρίζουν ικανοποιητικά τα διαθέσιμα εργαλεία (aka C11).

 

Για το representation του 0 σε C11 μου κάνει εντύπωση που δεν το ανέφερε κανείς σε κείνη την ερώτηση παρόλο που έχουν παραθέσει άλλα quotes από C11. Αλλά δεν έχω το πρότυπο οπότε αρκούμαι σ' αυτά που ακούω από δεύτερο χέρι.

Το οποίο το έχει αναφέρει και ο ημίθεος (btw, κατά την εκτίμησή μου, στο παρόν φόρουμ υπάρχουν συμμετέχοντες ίσοι ή/και καλύτεροι από τους συμμετέχοντες στο SO... απλώς είναι μικρότερη η ποσοτική κλίμακα εδώ).

 

 

Ο δείκτης p είναι από μόνος του object (6.2.5/20) και έχει συγκεκριμένο τύπο. Για το pointer arithmetic κάνω quote το 6.5.6/2:

 

Είμαι σίγουρος πως καταλαβαίνεις τη διαφορά ανάμεσα στο "a pointer to an object type" και στην ίδια έκφραση χωρίς τη λέξη type μέσα.

 

Επιπλέον ξαναλέω πως τρέχοντας το ίδιο example που δίνεις στο ideone έτυχε να τυπώσει 0 4. Προφανώς αν πριν την πρόσθεση συγκρίνω με NULL θα δώσει true. Αλλά όπως έχω βαρεθεί να κάνω quote το quote του ημίθεου, είναι δεδομένο πως pointer to object  (χωρίς type εδώ) και null pointer επιβάλλεται να κάνουν compare unequal. Άρα ο p δεν μπορεί να είναι pointer to object. Είναι σκέτο pointer στην καθομιλουμένη, ή object of type pointer to integer σε standardese.

 

Τέλος, η 6.5.3.2/4 λέει σχετικά με τον indirection operator *:

 

 

Είναι φανερό ότι το invalid value και το "points to an object" είναι αμοιβαία αποκλειόμενες περιπτώσεις. Σου γυρνάω λοιπόν την ερώτηση σχετικά με το παράδειγμα που έφερες και ρωτάω με τη σειρά μου: εφόσον υποστηρίζεις ότι όντως it points to an object χωρίς να έχεις κάνει initialize τον pointer, τότε (α) γιατί αν γράψω *p = 42 θα κρασάρουμε και (β) ποιά θα ήταν η (διαφορετική) περίπτωση που έχει invalid value?

 

Αν ακόμα δεν πείθεσαι take a step back και θα ίσως δεις ότι έτσι που το θέτω έχει λογική. Αν πάλι όχι, δε νομίζω πως έχει νόημα να ξαναλέμε τα ίδια και τα ίδια. Feel free να ρωτήσεις στο SO και να ποστάρεις το link.

Ούτε πείθομαι, ούτε αισθάνομαι την ανάγκη να step back, ούτε χρειάζεται να ποστάρω στο SO. Έχω κάνει κι εγώ quotes σε προηγούμενο ποστ αυτής της σελίδας κι έχω κοκκινήσει τα επίμαχα σημεία. Επίσης για το cast έχω εξηγήσει περισσότερες της μιας φοράς πως δεν υποστηρίζω ότι δημιουργεί object αλλά ότι λέει στον compiler να κάνει treat το casted σαν να ήταν δείκτης σε object.

 

Θεωρώ πως μπερδεύεις τον όρο pointer στη C με τον όρο reference σε γλώσσες όπως η Java και η C++

 

Σχετικά με την ερώτησή σου, σε C context invalid pointer είναι ένας uninitialized pointer, ένας freed pointer, ένας pointer με τιμή μια διεύθυνση που δεν ανήκει στο address-space σου (οπότε αν η 42 είναι μέσα στο address space σου -σε κάποια πλατφόρμα- δεν πρόκειται να κρασάρεις). Επίσης το NULL είναι special case των invalid pointers. Good read: http://www.eskimo.com/~scs/cclass/int/sx7.html

 

@imitheos:

 

Ναι, για το παράδειγμα που φέρνεις με το VS συμφωνώ κι εγώ (όπως γνωρίζεις ποτέ δεν το προτείνω σε όποιον ρωτάει για C compiler).

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

Το προηγούμενο πρότυπο είναι χαμένος χρόνος όταν το ενδιαφέρον σου είναι ακαδημαϊκό. Όταν ασχολείσαι επαγγελματικά, τότε πρώτη προτεραιότητα έχει το υπάρχον code base και τα διαθέσιμα εργαλεία. Επαγγελματικά χαμένος χρόνος είναι να βιάζεσαι να χρησιμοποιήσεις ένα πρότυπο που δεν το υποστηρίζουν ικανοποιητικά τα διαθέσιμα εργαλεία (aka C11).

 

Το φαντάστηκα πως θα πεις κάτι τέτοιο και γι' αυτό είπα "σηκώνει συζήτηση". Καταλαβαίνω το point σου, καταλαβαίνεις το δικό μου. Όταν μιλάμε συγκεκριμένα για ενασχόληση με το πρότυπο και όχι για code base γενικότερα νομίζω πως το επιχείρημά σου εξασθενεί κάπως. Αλλά στην τελική είναι και θέμα προτίμησης/κατεύθυνσης.

 

(btw, κατά την εκτίμησή μου, στο παρόν φόρουμ υπάρχουν συμμετέχοντες ίσοι ή/και καλύτεροι από τους συμμετέχοντες στο SO... απλώς είναι μικρότερη η ποσοτική κλίμακα εδώ).

 

Ούτε γι' αστείο. Η ψυχούλα μου το ξέρει πως αισθάνομαι ότι περπατάω ανάμεσα σε γίγαντες όταν απαντάω κάποιες ερωτήσεις που έχουν ζουμί. Δοκίμασέ το και πες μου εσύ τι αίσθηση αποκομίζεις.

 

Εξαρτάται βέβαια από το τι εννοείς "συμμετέχοντες στο SO". Εντελώς χοντρικά κάτω από 50Κ και πάνω από 50Κ είναι δύο διαφορετικοί κόσμοι.

 

Ούτε πείθομαι, ούτε αισθάνομαι την ανάγκη να step back, ούτε χρειάζεται να ποστάρω στο SO. Έχω κάνει κι εγώ quotes σε προηγούμενο ποστ αυτής της σελίδας κι έχω κοκκινήσει τα επίμαχα σημεία. Επίσης για το cast έχω εξηγήσει περισσότερες της μιας φοράς πως δεν υποστηρίζω ότι δημιουργεί object αλλά ότι λέει στον compiler να κάνει treat το casted σαν να ήταν δείκτης σε object.

 

Οπότε ας το αφήσουμε εδώ, μου φαίνεται πως έχουμε ξεπεράσει προ πολλού το σημείο όπου μπορεί να βγει κάτι θετικό. Πάντως αν θέλεις δεν έχω πρόβλημα να γράψεις εσύ την ερώτηση και να την ποστάρω εγώ έτσι για να δούμε τι θα μας πουν.

 

Σχετικά με την ερώτησή σου, σε C context invalid pointer είναι ένας uninitialized pointer, ένας freed pointer, ένας pointer με τιμή μια διεύθυνση που δεν ανήκει στο address-space σου (οπότε αν η 42 είναι μέσα στο address space σου -σε κάποια πλατφόρμα- δεν πρόκειται να κρασάρεις).

 

Αλλά θες να με σκάσεις. Πρώτον: αφού στο παράδειγμά σου δίνεις uninitialized pointer, και αφού παραδέχεσαι ότι είναι invalid, άρα αυτό δε σημαίνει αυτόματα ότι δεν είναι pointer to object βάσει του quote που έδωσα παραπάνω;

 

Και δεύτερον: ένας pointer που δείχνει "στο θεό" (αλλά μέσα στο address space) είναι valid? Δηλαδή αν κάνω αυτό δεν είναι π.χ. invalid? Και αφού μπορώ να κάνω μετά pointer arithmetic πάνω στον p, τελικά το παράδειγμα που έδωσες τι αποδεικνύει?

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

... 

Αλλά θες να με σκάσεις. Πρώτον: αφού στο παράδειγμά σου δίνεις uninitialized pointer, και αφού παραδέχεσαι ότι είναι invalid, άρα αυτό δε σημαίνει αυτόματα ότι δεν είναι pointer to object βάσει του quote που έδωσα παραπάνω;

Κάτσε τώρα γιατί σε έχασα. Για ποιο από όλα τα παραδείγματα μιλάμε;

 

Και δεύτερον: ένας pointer που δείχνει "στο θεό" (αλλά μέσα στο address space) είναι valid? Δηλαδή αν κάνω αυτό δεν είναι π.χ. invalid? Και αφού μπορώ να κάνω μετά pointer arithmetic πάνω στον p, τελικά το παράδειγμα που έδωσες τι αποδεικνύει?

Το συγκεκριμένο δεν είναι invalid, αλλά είναι incompatible τα types τους. Μάλιστα αν το θυμάμαι σωστά απ'εξω αυτό ακριβώς κάνει (με compatible types) και ο King στο 'Advanced C Programming 2nd Edition" σε ένα memory viewer που δίνει σαν παράδειγμα... το άνοιξα για να δω αν όντως είναι εκεί, αλλά δυστυχώς το pdf είναι από φωτοτυπία οπότε δεν λειτουργεί το search.

 

Θυμάμαι πως δείχνει στον χρήστη σε ποια διεύθυνση ξεκινάει η main function και του ζητάει πόσα bytes από εκεί και μετά θέλει να δει σε dump... ίσως να είναι σε άλλο βιβλίο όμως.

 

Πάντως το τελευταίο link που έδωσα πριν εξηγεί πολύ καλά τι θεωρείται valid και τι invalid pointer στην C, πολύ καλύτερα από ότι μπορώ να το εξηγήσω εγώ.

 

Για το SO, δεν έχω πρόβλημα να το ποστάρεις αν θες σαν ερώτηση και να ποστάρεις το link να το παρακολουθήσουμε μετά (ίσως και να γράψω κιόλας)... αλλά γενικώς μου την σπάει το SO. Όπως και να έχει όμως, νομίζω η βασική μας διαφωνία είναι πως θεωρείς ότι έγραψα πως το cast δημιουργεί object, ενώ εγώ έγραψα πως λέει στον compiler να κάνει treat το casted σαν να ήταν δείκτης σε object.

 

Μισό να τσεκάρω κάτι σε C++ context, που ίσως μας δώσει μια κοινή βάση συνεννόησης... νομίζω υπάρχει ένα overload του new operator που δεν κάνει allocate... πάω να το βρω (αν υπάρχει) και επανέρχομαι.

 

...

Μισό να τσεκάρω κάτι σε C++ context, που ίσως μας δώσει μια κοινή βάση συνεννόησης... νομίζω υπάρχει ένα overload του new operator που δεν κάνει allocate... πάω να το βρω (αν υπάρχει) και επανέρχομαι.

Όντως υπάρχει (το placement, No 3), αλλά τελικά δεν έχει την "αντιστοιχία" που νόμιζα με τα unallocated C pointers, γιατί εκείνο θέλει να του περάσεις σαν όρισμα έναν ήδη allocated pointer... οπότε άνθρακας ο θησαυρός.

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

Κάτσε τώρα γιατί σε έχασα. Για ποιο από όλα τα παραδείγματα μιλάμε;

Γι' αυτό

 

 

 

 

Το συγκεκριμένο δεν είναι invalid, αλλά είναι incompatible τα types τους. Μάλιστα αν το θυμάμαι σωστά απ'εξω αυτό ακριβώς κάνει (με compatible types) και ο King στο 'Advanced C Programming 2nd Edition" σε ένα memory viewer που δίνει σαν παράδειγμα... το άνοιξα για να δω αν όντως είναι εκεί, αλλά δυστυχώς το pdf είναι από φωτοτυπία οπότε δεν λειτουργεί το search.

 

Συγγνώμη αλλά κάνεις πολύ μεγάλο λάθος και μάλιστα για πολλούς λόγους.

 

Πρώτον και προφανέστερο, 6.5.6 (pointer addition):

 

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

 

Επομένως ο pointer στη main αντιμετωπίζεται σαν pointer στο πρώτο στοιχείο ενός πίνακα από τέτοιους pointers μήκους 1.

 

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

 

Εφόσον το +10 που δίνω είναι μεγαλύτερο από +1 νομίζω τα σχόλια περιττεύουν. UB.

 

Δεύτερον, ακόμα κι αν αυτό δεν ήταν UB και πάλι δε μπορείς σε καμία περίπτωση να ξέρεις αν είναι valid pointer ή όχι (6.5.3.3):

 

Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.

 

Προφανές. Δεν ξέρεις καθόλου αν είναι properly aligned.

 

Συνοψίζοντας δεν ξέρω τι λέει ο King αλλά δε με πολυαπασχολεί κιόλας because the standard.

 

 

Πάντως το τελευταίο link που έδωσα πριν εξηγεί πολύ καλά τι θεωρείται valid και τι invalid pointer στην C, πολύ καλύτερα από ότι μπορώ να το εξηγήσω εγώ.

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

 

Αν δε μπορείς να πεις "an undefined pointer is a pointer that X Y Z" δεν έχεις εξηγήσει τίποτα (πάντα με το δική μου αντίληψη της λέξης).

 

Όπως και να έχει όμως, νομίζω η βασική μας διαφωνία είναι πως θεωρείς ότι έγραψα πως το cast δημιουργεί object, ενώ εγώ έγραψα πως λέει στον compiler να κάνει treat το casted σαν να ήταν δείκτης σε object.

Φυσικά και όχι. Θεωρώ ότι χρησιμοποιείς την έκφραση "pointer to object" λανθασμένα γιατί οι invalid pointers δεν είναι pointers to object. Και το undefined behavior εξορισμού επίσης δε μπορείς να λες ότι παράγει pointer to object.

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

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

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

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

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

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

Σύνδεση

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

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

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