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

Ερωτήσεις για C


capoelo

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

Βασικά εγώ απλώς έκανα cast το αποτέλεσμα της αφάιρεσης σε long int. Το data-type για αποθήκευση αφαίρεσης δεικτών είναι το ptrdiff_t που ορίζεται στο stddef.h και είναι signed. Οι δείκτες αυτοί κάθε αυτοί είναι size_t αν δεν κάνω λάθος.

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

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

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

Δημοσ. (επεξεργασμένο)

:lol:

 

Κάτι άσχετο, γιατί το OpenBSD στον κώδικα της strcasecmp() ( και της strncasecmp() ) χρησιμοποιεί τον συγκεκριμένο πίνακα από unsigned char για να κάνει τις συγκρίσεις των χαρακτήρων, αντί να τα κάνει απευθείας cast σε (unisigned char)?

 

EDIT:

 

Κατάλαβα τι κάνει ο πίνακας, από τον 127ο χαρακτήρα και μετά του ASCII table, κάνει treat τις τιμές ως -128, -127 ... -1.

 

Γιατί όμως, τι πρόβλημα υπάρχει με το απευθείας cast σε (unsigned char)?

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

:lol:

 

Κάτι άσχετο, γιατί το 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 οπότε και ο πίνακας)
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν μπορώ να σου απαντήσω με σιγουριά, αλλά η λογική μου λέει ότι είναι False κι όχι UB.

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

Επαναλαμβάνω δεν το γνωρίζω, εικασίες κάνω... :P

 

Eχω την εντυπωση πως οι εικασιες σου εχουν λογικη αρα μας κανουν.  Οντως δεν μπορεις να ξερεις τι μπορει να παιξει στην αφαιρεση 2 δεικτων.... πχ σε ποια διευθυνση μνημης μπορεις να βρεθεις αν αυτη η μνημη δεν ειναι οριοθετημενη μεσα σε περιοχη που εχεις δεσμευσει για παραδειγμα με την δηλωση και αρχικοποιηση ενος πινακα 4 ακεραιων οποτε αφαιρωντας τον δεικτη που δειχνει στο 3ο απο τον δεικτη που δειχνει 1ο στοιχειο ξερεις πως θα παρεις την διευθυνση του 2ου.

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

Το κρίσιμο ερώτημα είναι σε τι νομίζεις πως θα σε εξυπηρετήσει το να αφαιρείς δυο δείκτες που δείχνουν σε άσχετα structures;

 

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

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

Μα δεν ειπα εγω οτι θα με εξυπηρετησει σε κάτι . Συμφωνω οτι εχει νοημα οταν δειχνουν στον ιδιο πινακα και οι 2 αλλωστε το εγραψα και εγω αυτο.

 

Καλη χρονια + ευτυχισμενο το νεο ετος με υγεια και χαρα για ολους μας. :D

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

** Πρακτικά ισχύουν όσα έχουν ήδη ειπωθεί. Θα απαντήσω καθαρά φιλοσοφικά για το τι γίνεται θεωρητικά **

 

Όταν συγκρίνουμε 2 δεικτες που δειχνουν σε διαφορετικούς πινακες το αποτελεσμα ειναι undefined ή απλα 0?

Η ισότητα αυτή δεν γίνεται να είναι ποτέ αληθής γιατί οι str1 και str2 έχουν την τιμή της διεύθυνσης της μνήμης που είναι αποθηκευμένοι οι δύο πίνακες.

Ακόμα κι αν είχες ορίσει:

str1[]="abc", str2[]="abc";

Οι str1 και str2 έχουν διαφορετική τιμή.

Είναι unspecified behavior επειδή μπορεί κάποιος compiler να χρησιμοποιήσει ένα instance και για τα δύο strings οπότε να δώσει true και άλλος compiler να δημιουργήσει 2 strings οπότε να δώσει false. Αυτό όμως μόνο στην παραπάνω περίπτωση γιατί οι τύποι είναι "συμβατοί". Αν οι δείκτες έδειχναν σε διαφορετικούς τύπους τότε θα ήταν undefined.

  

Δεδομενου πως οι δείκτες είναι απρόσημες ακέραιες τιμές (μνήμης), γιατί να έχουμε UB? Το που δείχνουν δεν έχει σχέση με την αφαίρεση των διευθύνσεων αυτών που δείχνουν.

Αυτό γίνεται μόνο σε αρχιτεκτονικές με "flat" μνήμη. Δεν ισχύει γενικά ότι μπορείς να αντιμετωπίσεις ένα δείκτη σαν μια ακέραια τιμή.

 

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

Επαναλαμβάνω δεν το γνωρίζω, εικασίες κάνω... :P

 

 

whatever *p = στον γάμο του καραγκιόζη;
whatever *q = στου έξω από 'δω την μάνα;
printf( "%ld\n, (long int)(p-q) );  // no problem
 

 

 

 

 

 

Αυτό είναι undefined. Σε αντίθεση με τον == που χρειάζεται απλά συμβατούς τύπους (ή null), οι περισσότεροι άλλοι τελεστές συμπεριλαμβανομένου και του - μπορούν να δουλέψουν μόνο αν οι δύο δείκτες αναφέρονται στο ίδιο αντικείμενο ή ένα στοιχείο πέρα από το τέλος του αντικειμένου. Εδώ έχουμε δείκτες που δείχνουν σε εντελώς άσχετα αντικείμενα οπότε δεν μπορούν να αφαιρεθούν (ακόμη και αν δεν προσπελάσουμε το αποτέλεσμα).

Η πράξη αυτή καθ'αυτή δεν είναι πρόβλημα και συμφωνώ, αυτό που λέω είναι για το τι γίνεται όταν πάς να κάνεις access τον (p-q). ( Δηλαδή το *(p-q) )

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

 

Το ζουμί είναι ότι sizeof(ακαιρεος) < sizeof(δεικτης) :P

Είτε σκέτο είτε μαζί με το ίσον, αυτό δεν το εγγυάται κανείς.

:lol:

 

Κάτι άσχετο, γιατί το 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 θα βρεθούν ίσα.
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

...

Αυτό είναι undefined. Σε αντίθεση με τον == που χρειάζεται απλά συμβατούς τύπους (ή null), οι περισσότεροι άλλοι τελεστές συμπεριλαμβανομένου και του - μπορούν να δουλέψουν μόνο αν οι δύο δείκτες αναφέρονται στο ίδιο αντικείμενο ή ένα στοιχείο πέρα από το τέλος του αντικειμένου.

...

Στο αντικείμενο 'whatever' αναφέρονται οι p και q στο παράδειγμα που έδωσα (αλλιώς θα έγραφα whatever1, whatever2).

 

Σωστός όμως για το flat memory (θα μπoρούσαν να ήταν και struct, π.χ. ένα page number και ένα offset).

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

Στο αντικείμενο '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 δείχνουν σε διαφορετικά αντικείμενα (α και β) οπότε δεν μπορούν να αφαιρεθούν. Αν εννοούσες κάτι άλλο πάω πάσο.

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

EDIT:

 

Γκουγκλάροντας λιγάκι όμως (γιατί με έτρωγε :P) βρήκα αυτό...

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).

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

EDIT:

 

Γκουγκλάροντας λιγάκι όμως (γιατί με έτρωγε :P) βρήκα αυτό...

 

 

 

Ναι, αυτό εννούσα. Είναι σίγουρο πως είναι undefined? (το έχεις ψάξει στο πρότυπο; εγώ όχι, αλλά από ότι θυμάμαι δεν είναι undefined).

Δεν βλέπω να αναιρεί η glibc αυτό που είπα (άσε που η glibc δεν είναι και η καλύτερη πηγή για πρακτικές που τηρούν το πρότυπο :P). Λέει ότι η αφαίρεση δύο δεικτών έχει πάντα ακέραιο αποτέλεσμα και ότι αυτό έχει τύπο 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.

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

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

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