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

Ερώτηση για signed int στη C


capoelo

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

Έχω την εξής απορία:δοθέντος αυτού του αποσπάσματος κώδικα

 

>
for(int i=0;i<33000;i++)
 printf("%d\n",i);

 

μου τρέχει μέχρι την τιμή 32999.Κανονικά δεν θα έπρεπε να σταματήσει στην τιμή 32767;

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

Αν θέλεις να έχεις απόλυτο έλεγχο στο εύρος τιμών των τύπων που χρησιμοποιείς, μπορείς να χρησιμοποιήσεις τους fixed-size τύπους της C99, με #include <stdint.h> ή/και #include <inttypes.h>.

 

Οπότε αν θέλεις να περιορίσεις το i σε 16μπιτες τιμές, το παράδειγμά σου γίνεται κάπως έτσι...

 

>
for (int16_t i=0; i < 33000; i++)
  ...

 

και προφανώς από INT16_MAX και πάνω θα πάρεις garbage αν στο περάσει ο compiler. Ευτυχώς chances are πως δεν θα σου το περάσει, και θα σου βγάλει warning για overflow.

 

Για πιο σίγουρα όμως, consider κάτι σαν κι αυτό...

 

>
for (int16_t i=0; i < INT16_MAX; i++)
  ...

 

Το πρόβλημα είναι πως οι primitive τύποι έχουν implementation dependent εύρος τιμών. Δηλαδή, σε άλλες πλατφόρμες/compilers ένας int μπορεί να έχει 16μπιτο εύρος, σε άλλη να έχει 32μπιτο και σε άλλη 64μπιτο.

 

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

 

Έτσι, για παράδειγμα, για τον τύπο int το πρότυπο σου εγγυάται πως έχει παντού τουλάχιστον 16μπιτο εύρος τιμών. Μπορεί στην πλατφόρμα σου να έχει 32μπιτο εύρος.

 

Αν το θυμάμαι σωστά, το πρότυπο επιβάλλει στους κατασκευαστές να παρέχουν pre-processor constants ή macros για τις μέγιστες (αλλά και τις ελάχιστες) τιμές που μπορεί να πάρει ο κάθε τύπος στην υλοποίηση του compiler τους.

 

Αυτά τα όρια βρίσκονται στο header file <limits.h> για τα primitive types. Για τους fixed-size integers που εισήχθησαν στην C99 υπάρχουν στο header file <stdint.h>

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

Έχω την εξής απορία:δοθέντος αυτού του αποσπάσματος κώδικα

 

>
for(int i=0;i<33000;i++)
printf("%d\n",i);

 

μου τρέχει μέχρι την τιμή 32999.Κανονικά δεν θα έπρεπε να σταματήσει στην τιμή 32767;

 

Όχι. Στην πλατφόρμα σου (όπως και στις περισσότερες) ο int φτάνει μέχρι ~2.1 δις γιατί είναι 32 bit ποσότητα, αλλά ακόμα κι αν δεν έφτανε τότε πάλι το πρόγραμμα δε θα σταματούσε (τουλάχιστον ομαλά) επειδή τερματίζοντας το κοντέρ το i θα έπαιρνε την ελάχιστη τιμή για int, που βέβαια είναι κι αυτή μικρότερη από την μέγιστη στην οποία μόλις τερμάτισες το κοντέρ, άρα endless loop ή χειρότερα.

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

Αν θέλεις να έχεις απόλυτο έλεγχο στο εύρος τιμών των τύπων που χρησιμοποιείς, μπορείς να χρησιμοποιήσεις τους fixed-size τύπους της C99, με #include <stdint.h> ή/και #include <inttypes.h>.

 

+1

 

Βάζεις τους standard "τύπους" και ξενοιάζεις. Στο stdint υπάρχουν τα typedef για τους τύπους και στο inttypes (που καλεί εσωτερικά και το stdint) υπάρχουν τα format για το printf. Μπορεί να ακούγεται χαζό αλλά υπάρχουν πολλοί κώδικες που χρησιμοποιούν τους τύπους πχ int32_t αλλά στο printf βάζουν "%d κτλ" αντί για "%"PRId32" κτλ" οπότε πάει άχρηστη η portability του τύπου.

 

>
for (int16_t i=0; i < INT16_MAX; i++)
  ...

Αυτά τα όρια βρίσκονται στο header file <limits.h> για τα primitive types. Για τους fixed-size integers που εισήχθησαν στην C99 υπάρχουν στο header file <stdint.h>

 

Να επισημάνουμε για τα όρια πως ενώ το size_t σαν τύπος υπήρχε και στην C89, μάλλον από λάθος δεν είχε οριστεί το όριο του. Έτσι το SIZE_MAX πρωτο-ορίστηκε στην C99 (και σε πολλές υλοποιήσεις υπάρχει στο stdint.h και όχι στο limits.h). Οπότε αν κάποιος θέλει να χρησιμοποιήσει το SIZE_MAX να πάρει τα ανάλογα μέτρα.

 

Έτσι, για παράδειγμα, για τον τύπο int το πρότυπο σου εγγυάται πως έχει παντού τουλάχιστον 16μπιτο εύρος τιμών. Μπορεί στην πλατφόρμα σου να έχει 32μπιτο εύρος.

 

Όντως το πρότυπο αναφέρει τις ελάχιστες τιμές που πρέπει να υποστηρίζει μια υλοποίηση. Ένας int (όπως και ένας short) πρέπει να υποστηρίζει τιμές τουλάχιστον -32768 - 32767 οπότε και θα έχει τουλάχιστον 16bit όπως είπε ο migf1.

 

[Η άχρηστη πληροφορία της ημέρας]

Το πρότυπο μιλάει πάντα για τιμές και όχι για bits. Επειδή η C κοιτάζει πάντα να έχει καλές επιδόσεις αυτό σημαίνει πως όλοι οι compilers θα υλοποιήσουν τους τύπους με τέτοιο εύρος όσο και οι τιμές που θέλουν να υποστηρίξουν. Δηλαδή αν έχουμε int με μέγιστο το 32767 αυτό σημαίνει ότι σχεδόν παντού θα είναι 16bit. Δεν εμποδίζει όμως κανείς τον compiler να υλοποιεί τον int με 19bit ή 45bit ή οτιδήποτε και από αυτά να χρησιμοποιούνται μόνο τα 16 και τα άλλα να κάθονται άχρηστα.

 

Δηλαδή μπορεί να έχουμε INT_MAX 32767 και το sizeof(int) να μας δώσει 4 αντί για 2.

[/Η άχρηστη πληροφορία της ημέρας]

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

@imitheos ίσως άχρηστη στην πράξη αλλά σίγουρα ενδιαφέρουσα. Δεν το είχα υπόψη, θυμάσαι μήπως παράγραφο για να μην το ψάχνω manually;

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

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

@imitheos ίσως άχρηστη στην πράξη αλλά σίγουρα ενδιαφέρουσα. Δεν το είχα υπόψη, θυμάσαι μήπως παράγραφο για να μην το ψάχνω manually;

 

Δεν θυμάμαι αν αναφέρεται σε μία παράγραφο ή συμπεραίνεται από 2-3 παραγράφους. Θυμάμαι σίγουρα ότι επιτρέπεται να υπάρχουν όσα άχρηστα bits θέλουμε και μπορούν να έχουν ό,τι τιμή θέλουμε με μοναδικό περιορισμό ότι αν γράψουμε σε όλα τα bits (χρήσιμα + άχρηστα) παντού 0 θα πρέπει να είναι σωστή αναπαράσταση του μηδενός.

 

Ένα κλασικό παράδειγμα που έχω διαβάσει είναι οι Cray. Όπως αναφέρεται εδώ βλέπουμε ότι ένας short απεικονίζει τιμές εύρους 32bit αλλά καταλαμβάνει 64bit καθώς και οι δείκτες εκτός από void και char ακολουθούν την ίδια τακτική.

 

Εκτός από την επίσημη τεκμηρίωση, το ίδιο αναφέρει και η βιβλιοθήκη MP που είναι για arbitrary precision αριθμητική:

This example assumes the full sizeof bytes are used for data in the given type, which is usually true, and certainly true for unsigned long everywhere we know of. However on Cray vector systems it may be noted that short and int are always stored in 8 bytes (and with sizeof indicating that) but use only 32 or 46 bits. The nails feature can account for this, by passing for instance 8*sizeof(int)-INT_BIT.

 

 

Edit:

Padding bits are user-accessible in an unsigned integer type. For example, suppose a machine

uses a pair of 16-bit shorts (each with its own sign bit) to make up a 32-bit int and the sign

bit of the lower short is ignored when used in this 32-bit int. Then, as a 32-bit signed

int, there is a padding bit (in the middle of the 32 bits) that is ignored in determining the value

of the 32-bit signed int. But, if this 32-bit item is treated as a 32-bit unsigned int, then

that padding bit is visible to the user’s program. The C committee was told that there is a

machine that works this way, and that is one reason that padding bits were added to C99.

Βρήκα και κάτι άλλο. Το rationale είναι το έγγραφο που βγαίνει μετά από έκδοση του προτύπου και εξηγεί γιατί πήρε η επιτροπή τις συγκεκριμένες αποφάσεις. Όπως διαβάζουμε λοιπόν αναφέρει πως εκτός ότι επιτρέπονται padding bits, αυτά θα πρέπει να είναι διαθέσιμα στον χρήστη αν μιλάμε για unsigned τύπο και πως εισήχθησαν γιατί υπήρχαν ήδη αρχιτεκτονικές που δούλευαν με αυτό τον τρόπο.

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

Στην αρχιτεκτονικη ενος ΗΥ οι παραστάσεις που δίνουν τον μέγιστο και ελαχιστο αριθμο που μπορει να παρασταθει απο το συγκεκριμενο υπολογιστικο συστημα ισχυουν κανονικα. Αυτες ομως έχουν να κάνουν με το εύρος ενος καταχωρητη .

Ο sizeof δεν νομιζω για εναν τυπο να παράγει αυτο το εύρος.

 

Για παράδειγμα αν είσαι σε ενα 3 bit συστημα τοτε θα έχεις :

 

για μέγιστο θετικό αριθμό που μπορεί να αναπαρασταθεί να δίνεται απο τον τύπο 2^n-1 - 1 . Για n=3 λοιπον θα έχουμε 2^3-1 - 1 = 2^2 - 1 = 3 (και φυσικα 8 συνδυασμους αυτων) . O μέγιστος αρνητικός αριθμός που μπορεί να αναπαρασταθεί είναι -(2^n-1 - 1) = -(2^3-1 - 1) = -(2^2-1) = -3

 

Αλλα οπως ειπε και παραπανω ο ημιθεος το προτυπο μιλαει για εύρος τιμών και ΟΧΙ για bits.

 

υ.γ Τα εγραψα ολα αυτα οχι επειδη η C έχει κάποια σχέση με τους καταχωρητές και την αρχιτεκτονικη ενος υπολογιστη αλλα επειδη ισως μπερδεύτηκες απο τον τύπο υπολογισμου των bits που χρησιμοποιειται στην αρχιτεκτονικη.

 

υ.γ2 Τεινω να πιστευω πως ειναι καλυτερο να διαβαζουμε απευθειας το προτυπο της C παρα τα βιβλια της :D

κανα λινκ προχειρο με το προτυπο παιζει? με μια ερευνα που εκανα στο νετ δεν βρηκα κατι.... :/

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

...

υ.γ2 Τεινω να πιστευω πως ειναι καλυτερο να διαβαζουμε απευθειας το προτυπο της C παρα τα βιβλια της :D

κανα λινκ προχειρο με το προτυπο παιζει? με μια ερευνα που εκανα στο νετ δεν βρηκα κατι.... :/

 

Δεν είναι καλή ιδέα, γιατί τα πρότυπα είναι γεμάτα παραπομπές, ορολογίες, footnotes, rationale notes, κλπ. Το C99 μπορείς να το βρεις εδώ: http://www.iso-9899.info/wiki/The_Standard

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

Με σκάλωσε παντως λιγο το οτι ενας short μπορει να αναπαρασταθει με 32 bit αλλα να καταλαμβανει 64.... τα αλλα 32 που χρησιμευουν ακριβως δηλαδη? Το 64 θα μπορεσει να φανει στον προγραμματιστη αν εφαρμοσει sizeof ? ή ειναι εσωτερικη υποθεση του compiler?

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

Δεν είναι καλή ιδέα, γιατί τα πρότυπα είναι γεμάτα παραπομπές, ορολογίες, footnotes, rationale notes, κλπ. Το C99 μπορείς να το βρεις εδώ: http://www.iso-9899....ki/The_Standard

 

Μόλις βρήκα link και για το N1570 draft του ISO C11: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

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

Με σκάλωσε παντως λιγο το οτι ενας short μπορει να αναπαρασταθει με 32 bit αλλα να καταλαμβανει 64.... τα αλλα 32 που χρησιμευουν ακριβως δηλαδη? Το 64 θα μπορεσει να φανει στον προγραμματιστη αν εφαρμοσει sizeof ? ή ειναι εσωτερικη υποθεση του compiler?

 

Γιατί να μην μπορεί ?

Τα άλλα bits δεν χρησιμεύουν πουθενά για αυτό και λέγονται "padding" bits. Για την ακρίβεια δεν χρησιμεύουν στον προγραμματιστή. Χρησιμεύουν στο ότι με αυτό το τρόπο έχουμε πιο γρήγορη εκτέλεση ή γιατί ο επεξεργαστής έχει συγκεκριμένο alignment και δεν μπορεί να χρησιμοποιήσει μικρότερο μέγεθος.

 

 

 

Μόλις βρήκα link και για το N1570 draft του ISO C11: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

 

C99

Draft του προτύπου με ενσωματωμένες βελτιωτικές αναθεωρήσεις:

C99+TC1+TC2 (Έγγραφο 1124 Μάιος 2005)

C99+TC1+TC2+TC3 (Έγγραφο 1256 Σεπτέμβριος 2007)

Defect Reports για το C99:

DR 201-345

Rationale:

Έκδοση 5.10

Τεράστιο έγγραφο "commentary" με όλες τις σελίδες του προτύπου και σχολιασμό αυτών:

Τελευταία Έκδοση 1.2

 

C11

Τελευταίο Draft:

C11 (Έγγραφο n1570 Απρίλιος 2011)

Defect Reports:

DR 400-413

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

Rationale δεν είμαι σίγουρος αλλά νομίζω δεν έχει βγει ακόμη.

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

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

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

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

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

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

Σύνδεση

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

Συνδεθείτε τώρα
  • Δημιουργία νέου...