migf1 Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 Βασικά εγώ απλώς έκανα cast το αποτέλεσμα της αφάιρεσης σε long int. Το data-type για αποθήκευση αφαίρεσης δεικτών είναι το ptrdiff_t που ορίζεται στο stddef.h και είναι signed. Οι δείκτες αυτοί κάθε αυτοί είναι size_t αν δεν κάνω λάθος. 1
bird Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 Το ζουμί είναι ότι sizeof(ακαιρεος) < sizeof(δεικτης)
migf1 Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 Έφαγες ένα ίσον... sizeof(ακέραιος) <= sizeof(δείκτης)
bird Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 Έφαγες ένα ίσον... sizeof(ακέραιος) <= sizeof(δείκτης) Τώρα πάω για μεσημεριανό και είπα να πάρω ένα ορεκτικό
migf1 Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 (επεξεργασμένο) Κάτι άσχετο, γιατί το OpenBSD στον κώδικα της strcasecmp() ( και της strncasecmp() ) χρησιμοποιεί τον συγκεκριμένο πίνακα από unsigned char για να κάνει τις συγκρίσεις των χαρακτήρων, αντί να τα κάνει απευθείας cast σε (unisigned char)? EDIT: Κατάλαβα τι κάνει ο πίνακας, από τον 127ο χαρακτήρα και μετά του ASCII table, κάνει treat τις τιμές ως -128, -127 ... -1. Γιατί όμως, τι πρόβλημα υπάρχει με το απευθείας cast σε (unsigned char)? Επεξ/σία 30 Δεκεμβρίου 2012 από migf1
Directx Δημοσ. 30 Δεκεμβρίου 2012 Δημοσ. 30 Δεκεμβρίου 2012 Κάτι άσχετο, γιατί το OpenBSD στον κώδικα της strcasecmp() ( και της strncasecmp() ) χρησιμοποιεί τον συγκεκριμένο πίνακα από unsigned char για να κάνει τις συγκρίσεις των χαρακτήρων, αντί να τα κάνει απευθείας cast σε (unisigned char)? EDIT: Κατάλαβα τι κάνει ο πίνακας, από τον 127ο χαρακτήρα και μετά του ASCII table, κάνει treat τις τιμές ως -128, -127 ... -1. Γιατί όμως, τι πρόβλημα υπάρχει με το απευθείας cast σε (unsigned char)? Από ότι είδα στο δίκτυο, υπάρχουν υλοποιήσεις της strcasecmp που χρησιμοποιούν απευθείας unsigned char (επίσης δίχως χρήση πίνακα μετατροπής) αντί char και cast σε unsigned char, υποθέτω ότι μάλλον οι συναρτήσεις του BSD γράφηκαν έτσι για λόγους συμβατότητας με παλαιότερους C μεταφραστές (ίσως σε μια εποχή που δεν υπήρχαν ακόμα οι tolower, toupper οπότε και ο πίνακας) 1
Star_Light Δημοσ. 31 Δεκεμβρίου 2012 Δημοσ. 31 Δεκεμβρίου 2012 Δεν μπορώ να σου απαντήσω με σιγουριά, αλλά η λογική μου λέει ότι είναι False κι όχι UB. Κι αυτό γιατί συγκρίνεις δύο διευθύνσεις μνήμης που δεν είναι κάτι "μεμπτό". Αντίθετα αν αφαιρέσεις δύο δείκτες, το αποτελεσμα αφενός μπορεί να είναι αρνητικό κι αφετέρου αν είναι θετικό μπορεί να βρεθείς σε "απαγορευμένες" περιοχές. Επαναλαμβάνω δεν το γνωρίζω, εικασίες κάνω... Eχω την εντυπωση πως οι εικασιες σου εχουν λογικη αρα μας κανουν. Οντως δεν μπορεις να ξερεις τι μπορει να παιξει στην αφαιρεση 2 δεικτων.... πχ σε ποια διευθυνση μνημης μπορεις να βρεθεις αν αυτη η μνημη δεν ειναι οριοθετημενη μεσα σε περιοχη που εχεις δεσμευσει για παραδειγμα με την δηλωση και αρχικοποιηση ενος πινακα 4 ακεραιων οποτε αφαιρωντας τον δεικτη που δειχνει στο 3ο απο τον δεικτη που δειχνει 1ο στοιχειο ξερεις πως θα παρεις την διευθυνση του 2ου.
migf1 Δημοσ. 31 Δεκεμβρίου 2012 Δημοσ. 31 Δεκεμβρίου 2012 Το κρίσιμο ερώτημα είναι σε τι νομίζεις πως θα σε εξυπηρετήσει το να αφαιρείς δυο δείκτες που δείχνουν σε άσχετα structures; Η αριθμητική δεικτών ως επί το πλείστον έχει νόημα όταν οι δείκτες κινούνται σε συγκεκριμένο πλαίσιο συνεχόμενης μνήμης (συνήθως array, αλλά όχι μόνο). 1
Star_Light Δημοσ. 31 Δεκεμβρίου 2012 Δημοσ. 31 Δεκεμβρίου 2012 Μα δεν ειπα εγω οτι θα με εξυπηρετησει σε κάτι . Συμφωνω οτι εχει νοημα οταν δειχνουν στον ιδιο πινακα και οι 2 αλλωστε το εγραψα και εγω αυτο. Καλη χρονια + ευτυχισμενο το νεο ετος με υγεια και χαρα για ολους μας.
imitheos Δημοσ. 1 Ιανουαρίου 2013 Δημοσ. 1 Ιανουαρίου 2013 ** Πρακτικά ισχύουν όσα έχουν ήδη ειπωθεί. Θα απαντήσω καθαρά φιλοσοφικά για το τι γίνεται θεωρητικά ** Όταν συγκρίνουμε 2 δεικτες που δειχνουν σε διαφορετικούς πινακες το αποτελεσμα ειναι undefined ή απλα 0? Η ισότητα αυτή δεν γίνεται να είναι ποτέ αληθής γιατί οι str1 και str2 έχουν την τιμή της διεύθυνσης της μνήμης που είναι αποθηκευμένοι οι δύο πίνακες. Ακόμα κι αν είχες ορίσει: str1[]="abc", str2[]="abc"; Οι str1 και str2 έχουν διαφορετική τιμή. Είναι unspecified behavior επειδή μπορεί κάποιος compiler να χρησιμοποιήσει ένα instance και για τα δύο strings οπότε να δώσει true και άλλος compiler να δημιουργήσει 2 strings οπότε να δώσει false. Αυτό όμως μόνο στην παραπάνω περίπτωση γιατί οι τύποι είναι "συμβατοί". Αν οι δείκτες έδειχναν σε διαφορετικούς τύπους τότε θα ήταν undefined. Δεδομενου πως οι δείκτες είναι απρόσημες ακέραιες τιμές (μνήμης), γιατί να έχουμε UB? Το που δείχνουν δεν έχει σχέση με την αφαίρεση των διευθύνσεων αυτών που δείχνουν.Αυτό γίνεται μόνο σε αρχιτεκτονικές με "flat" μνήμη. Δεν ισχύει γενικά ότι μπορείς να αντιμετωπίσεις ένα δείκτη σαν μια ακέραια τιμή. Αντίθετα αν αφαιρέσεις δύο δείκτες, το αποτελεσμα αφενός μπορεί να είναι αρνητικό κι αφετέρου αν είναι θετικό μπορεί να βρεθείς σε "απαγορευμένες" περιοχές. Επαναλαμβάνω δεν το γνωρίζω, εικασίες κάνω... whatever *p = στον γάμο του καραγκιόζη; whatever *q = στου έξω από 'δω την μάνα; printf( "%ld\n, (long int)(p-q) ); // no problem Αυτό είναι undefined. Σε αντίθεση με τον == που χρειάζεται απλά συμβατούς τύπους (ή null), οι περισσότεροι άλλοι τελεστές συμπεριλαμβανομένου και του - μπορούν να δουλέψουν μόνο αν οι δύο δείκτες αναφέρονται στο ίδιο αντικείμενο ή ένα στοιχείο πέρα από το τέλος του αντικειμένου. Εδώ έχουμε δείκτες που δείχνουν σε εντελώς άσχετα αντικείμενα οπότε δεν μπορούν να αφαιρεθούν (ακόμη και αν δεν προσπελάσουμε το αποτέλεσμα).Η πράξη αυτή καθ'αυτή δεν είναι πρόβλημα και συμφωνώ, αυτό που λέω είναι για το τι γίνεται όταν πάς να κάνεις access τον (p-q). ( Δηλαδή το *(p-q) )Όπως είπαμε, πρόβλημα αποτελεί και η απλή αφαίρεση χωρίς να προσπελάσεις το αποτέλεσμα. Αυτό θεωρητικά βέβαια όπως τόνισα στην αρχή. Το ζουμί είναι ότι sizeof(ακαιρεος) < sizeof(δεικτης) Είτε σκέτο είτε μαζί με το ίσον, αυτό δεν το εγγυάται κανείς. Κάτι άσχετο, γιατί το OpenBSD στον κώδικα της strcasecmp() ( και της strncasecmp() ) χρησιμοποιεί τον συγκεκριμένο πίνακα από unsigned char για να κάνει τις συγκρίσεις των χαρακτήρων, αντί να τα κάνει απευθείας cast σε (unisigned char)? EDIT: Κατάλαβα τι κάνει ο πίνακας, από τον 127ο χαρακτήρα και μετά του ASCII table, κάνει treat τις τιμές ως -128, -127 ... -1. Γιατί όμως, τι πρόβλημα υπάρχει με το απευθείας cast σε (unsigned char)? Σκέτο cast σε unsigned δεν αρκεί γιατί θέλεις σύγκριση χωρίς διάκριση κεφαλαιών-πεζών. Ο πίνακας δεν κάνει treat τιμές σαν -128, -127, κτλ αλλά μπαίνει για αυτό που είπε ο DirectX. Για κάποιο λόγο δεν ήθελαν να τρέξουν tolower και χρησιμοποιούν τον πίνακα. Αν δεις πχ τις θέσεις 65 και 97 έχουν και οι δύο τιμή \141 δηλαδή 97 που είναι το μικρό a και πάει λέγοντας. Έτσι συγκρίνοντας ένα A με ένα a θα βρεθούν ίσα. 1
migf1 Δημοσ. 1 Ιανουαρίου 2013 Δημοσ. 1 Ιανουαρίου 2013 ... Αυτό είναι undefined. Σε αντίθεση με τον == που χρειάζεται απλά συμβατούς τύπους (ή null), οι περισσότεροι άλλοι τελεστές συμπεριλαμβανομένου και του - μπορούν να δουλέψουν μόνο αν οι δύο δείκτες αναφέρονται στο ίδιο αντικείμενο ή ένα στοιχείο πέρα από το τέλος του αντικειμένου. ... Στο αντικείμενο 'whatever' αναφέρονται οι p και q στο παράδειγμα που έδωσα (αλλιώς θα έγραφα whatever1, whatever2). Σωστός όμως για το flat memory (θα μπoρούσαν να ήταν και struct, π.χ. ένα page number και ένα offset).
imitheos Δημοσ. 1 Ιανουαρίου 2013 Δημοσ. 1 Ιανουαρίου 2013 Στο αντικείμενο 'whatever' αναφέρονται οι p και q στο παράδειγμα που έδωσα (αλλιώς θα έγραφα whatever1, whatever2). Σωστός όμως για το flat memory (θα μπoρούσαν να ήταν και struct, π.χ. ένα page number και ένα offset). Ίσως δεν το κατάλαβα καλά αλλά έτσι που το έχεις, whatever δεν είναι ο τύπος του δείκτη ? Το αντικείμενο είναι αυτό στο οποίο ανήκει η διεύθυνση "γάμος του καραγκιόζη". whatever a[30]; whatever b[12]; whatever *p = a[16]; whatever *q = b[7]; Εδώ οι p και q δείχνουν σε διαφορετικά αντικείμενα (α και β) οπότε δεν μπορούν να αφαιρεθούν. Αν εννοούσες κάτι άλλο πάω πάσο.
migf1 Δημοσ. 1 Ιανουαρίου 2013 Δημοσ. 1 Ιανουαρίου 2013 EDIT: Γκουγκλάροντας λιγάκι όμως (γιατί με έτρωγε ) βρήκα αυτό... http://www.gnu.org/software/libc/manual/html_node/Important-Data-Types.html The result of subtracting two pointers in C is always an integer, but the precise data type varies from C compiler to C compiler Ίσως δεν το κατάλαβα καλά αλλά έτσι που το έχεις, whatever δεν είναι ο τύπος του δείκτη ? Το αντικείμενο είναι αυτό στο οποίο ανήκει η διεύθυνση "γάμος του καραγκιόζη". whatever a[30]; whatever b[12]; whatever *p = a[16]; whatever *q = b[7]; Εδώ οι p και q δείχνουν σε διαφορετικά αντικείμενα (α και β) οπότε δεν μπορούν να αφαιρεθούν. Αν εννοούσες κάτι άλλο πάω πάσο. Ναι, αυτό εννούσα. Είναι σίγουρο πως είναι undefined? (το έχεις ψάξει στο πρότυπο; εγώ όχι, αλλά από ότι θυμάμαι δεν είναι undefined).
imitheos Δημοσ. 1 Ιανουαρίου 2013 Δημοσ. 1 Ιανουαρίου 2013 EDIT: Γκουγκλάροντας λιγάκι όμως (γιατί με έτρωγε ) βρήκα αυτό... Ναι, αυτό εννούσα. Είναι σίγουρο πως είναι undefined? (το έχεις ψάξει στο πρότυπο; εγώ όχι, αλλά από ότι θυμάμαι δεν είναι undefined). Δεν βλέπω να αναιρεί η glibc αυτό που είπα (άσε που η glibc δεν είναι και η καλύτερη πηγή για πρακτικές που τηρούν το πρότυπο ). Λέει ότι η αφαίρεση δύο δεικτών έχει πάντα ακέραιο αποτέλεσμα και ότι αυτό έχει τύπο ptrdiff_t. Αυτό ισχύει όντως αλλά η λέξη κλειδί είναι το "αφαίρεση δεικτών". When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. Όπως βλέπουμε, η αφαίρεση δεικτών ορίζεται θεωρητικά μόνο μέσα στο ίδιο αντικείμενο. Επειδή λοιπόν δουλεύουμε μέσα στο ίδιο αντικείμενο, η αφαίρεση είναι πάντα η διαφορά των δύο στοιχείων i-j του αντικειμένου και για αυτό έχει πάντα ακέραιο τύπο. Με αυτό το σκεπτικό υποθέτω πως η glibc λέει όσα λέει. Ίσως θυμάμαι λάθος, αλλά νομίζω για αυτό το λόγο έγινε η εισαγωγή των τύπων intptr_t και uintptr_t. Αντίθετα με τον ptrdiff_t, αυτοί μπορούν να κρατήσουν την τιμή οποιουδήποτε δείκτη και να αφαιρεθούν χωρίς πρόβλημα. Επειδή όμως μπορεί να δείχνουν παντού έχουν νόημα μόνο σε flat αρχιτεκτονικές και ακόμη και τότε είναι optional γιατί η υλοποίησή τους μπορεί να έχει σημαντικό φόρτο για τον compiler.
Προτεινόμενες αναρτήσεις