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

C Overflow


Apanepai

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

Δημοσ.

Το γινόμενο δυο αριθμών δεν μπορεί να είναι σε μήκος μεγαλύτερο από το άθροισμα των μηκών των δύο παραγώντων. Άρα αν για το αποτέλεσμα δεσμεύεις μνήμη τόση όση είναι και για τους δύο παράγοντες μαζί είσαι εντάξει.

Δημοσ.

Polu swsta auto pou les kai me boithise arketa sti thewritiki katanoisi.

Ti kanoume omws otan oi eisagwgi twn arithmwn ginetai apo ton xristi?

Kamia idea gia ton kwdika?

 

Kati brika sxetika me tin LIMITS.H kai INTMAX alla den to polukatalaba.

Δημοσ.

Στην limits.h ορίζεται ο τύπος INT_MAX που είναι ο μεγαλύτερος ακέραιος που μπορεί να χωρέσει σε μια μεταβλητή τύπου int.

 

Βέβαια αν μιλάμε για userinput τα πράγματα δεν είναι τόσο εύκολα. Αν ας πούμε διαβάζεις με scanf() π.χ. scanf("%d", &i) οπου i (int) τότε η μεταβλητή i θα πάρει την μεγαλύτερη δυνατή τιμή (αν μιλάμε για 32 bit, +2,147,483,647) άσχετα αν ο χρήστης δώσει ένα πολύ μεγαλύτερο νούμερο. Δηλαδή είτε δώσει +2,147,483,650 είτε +3,999,999,999, η i θα ισούται με την τιμή που ήδη ανέφερα. Παρόμοια αποτέλεσματα θα έχεις αν διαβάζεις string και χρησιμοποιείς την atoi() για να επιστρέψεις int.

 

Βέβαια θα μπορούσες να διαβάζεις unsigned int που χωράει αριθμούς 0...2^32 αντί για 0...2^16-1 που χωράει ο τύπος int. Έτσι αν ας πούμε έχεις unsigned int a και int b μπορείς να έχεις μια δήλωση τύπου

>
unsigned int a;
int b;

[...]

scanf("%u", &a);

if (a > INT_MAX) printf("INT OVERFLOW!\n");
else b = a;

[...]

Δημοσ.
Στην limits.h ορίζεται ο τύπος INT_MAX που είναι ο μεγαλύτερος ακέραιος που μπορεί να χωρέσει σε μια μεταβλητή τύπου int.

 

Βέβαια αν μιλάμε για userinput τα πράγματα δεν είναι τόσο εύκολα. Αν ας πούμε διαβάζεις με scanf() π.χ. scanf("%d", &i) οπου i (int) τότε η μεταβλητή i θα πάρει την μεγαλύτερη δυνατή τιμή (αν μιλάμε για 32 bit, +2,147,483,647) άσχετα αν ο χρήστης δώσει ένα πολύ μεγαλύτερο νούμερο. Δηλαδή είτε δώσει +2,147,483,650 είτε +3,999,999,999, η i θα ισούται με την τιμή που ήδη ανέφερα. Παρόμοια αποτέλεσματα θα έχεις αν διαβάζεις string και χρησιμοποιείς την atoi() για να επιστρέψεις int.

 

Βέβαια θα μπορούσες να διαβάζεις unsigned int που χωράει αριθμούς 0...2^32 αντί για 0...2^16-1 που χωράει ο τύπος int. Έτσι αν ας πούμε έχεις unsigned int a και int b μπορείς να έχεις μια δήλωση τύπου

>
unsigned int a;
int b;

[...]

scanf("%u", &a);

if (a > INT_MAX) printf("INT OVERFLOW!\n");
else b = a;

[...]

 

 

 

Se euxaristw isoun arketa epeksigimatikos kai katatopistikos.

Den einai tuxaia to insomnia to num1 forum me tetoia member.

Kai pali euxaristw.

Δημοσ.

Πιστεύω πως η πιο σωστή αντιμετώπιση του προβλήματος είναι να ορίσουμε έναν νέο τύπο δεδομένων που στο ένα μέρος θα αποθηκεύεται το Most Significant Part του αριθμού και στο άλλο το Least. Έτσι δεν θα υπάρχει πρόβλημα με overflows σε καμία περίπτωση. Αυτό βέβαια απαιτεί προγραμματισμό σε low level αλλά μιας και αναφερόμαστε στην C, αυτή μας παρέχει την απαραίτητη ευελιξία που χρειαζόμαστε.

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

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

Δημοσ.

Υπάρχει και ο long long (συνήθως 64bit), μπορείς να τον χρησιμοποιήσεις σαν ενδιάμεσο αποτέλεσμα στη συνάρτηση, και έτσι αν το abs(αποτέλεσμα) είναι > 2^32 έχεις overflow.

 

Επίσης για αριθμούς με απεριόριστα ψηφία υπάρχει η βιβλιοθήκη της GNU: http://gmplib.org/

Δημοσ.

Πάντως για απλές περιπτώσεις Overflow / Underflow σε integers και εφόσον δεν μας ενδιαφέρει ιδιαίτερα το port του κώδικα σε διαφορετικά λειτουργικά ή επεξεργαστές, προτιμώ την γρήγορη και "καθαρή" λύση ελέγχου των CPU status flags (OF/SF) με την βοήθεια της Assembly (JO,JNS).

Δημοσ.
Πάντως για απλές περιπτώσεις Overflow / Underflow σε integers και εφόσον δεν μας ενδιαφέρει ιδιαίτερα το port του κώδικα σε διαφορετικά λειτουργικά ή επεξεργαστές, προτιμώ την γρήγορη και "καθαρή" λύση ελέγχου των CPU status flags (OF/SF) με την βοήθεια της Assembly (JO,JNS).

 

μηπως μπορεις να δωσεις ενα παραδειγματακι γιατι με μπερδεψες λιγο....

Δημοσ.

Ο πλέον αξιόπιστος έλεγχος για σφάλματα υπερχείλισης (overflow) ή υποχείλισης (underflow) όσον αφορά signed και unsigned integers (πχ. int, long κ.α.) στην C είναι ο έλεγχος της αντίστοιχης κατάστασης υπερχείλισης ή υποχείλισης του επεξεργαστή (CPU) με την συντονισμένη χρήση των 80x86 εντολών μηχανής «jo» (Jump if Overflow) και «jns» (Jump if Νοτ Signed) οι οποίες παρουσιάζουν την κατάσταση του επεξεργαστή (CPU Status Flags) ύστερα από την εκτέλεση πράξεων.

 

Η μεν «jo label» μεταφέρει την εκτέλεση του κώδικα μας στο σημείο που υποδεικνύει το label εάν το OF flag (OverFlow flag) του επεξεργαστή είναι ενεργό, δηλαδή 1 (set) ενώ η «jns label» μεταφέρει την εκτέλεση του κώδικα μας στο σημείο που υποδεικνύει το label εάν το SF flag (Sign flag) του επεξεργαστή είναι ανενεργό, δηλαδή 0 (clear).

 

Συγκεκριμένα, οι εντολές «jo» και «jns» πρέπει να χρησιμοποιούνται κάθε φορά που τελείτε μια οποιαδήποτε πράξη και έχετε υπόνοια πως θα μπορούσε να υπάρξει σφάλμα Overflow ή Underflow.

 

Σε περίπτωση λοιπόν που ο 80x86 εντοπίσει Overflow το OF flag και το SF flag γίνονται set (δηλαδή 1), αντίθετα αν ο 80x86 εντοπίσει Underflow το OF flag γίνεται set (δηλαδή 1) αλλά το SF flag γίνεται clear (δηλαδή 0).

 

Συνεπώς, στην πρώτη περίπτωση (Overflow) αρκεί η χρήση της «jo» για να εντοπισθεί το πρόβλημα, στην δεύτερη περίπτωση (Underflow) όμως θα πρέπει αφού επιβεβαιώσετε πως υπάρχει Overflow με την «jo» να κάνετε έναν ακόμα έλεγχο με την «jns» ώστε να διαπιστώσετε εάν το Overflow που υποδεικνύει η «jo» είναι Underflow οπότε σε αυτή την περίπτωση το SF flag θα είναι clear (δηλαδή 0).

 

Ακολουθεί κώδικας γραμμένος σε CodeGear Turbo C++ Explorer που υλοποιεί τον παραπάνω συλλογισμό στην ρουτίνα _CPUMathError (Assembly μορφής 32bit):

 

>
//-Overflow/Underflow in C & Assembly-----------------------------------------
// Directx.

#include <stdio.h>
#include <values.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif

//---------------------------------------------------------------------------
int _CPUMathError(void);

#ifdef __BORLANDC__
#pragma argsused
#endif
int main(int argc, char* argv[])
{                              //   0         1           2
static char *pszResult[] = { "Normal","Overflow","Underflow" };

// Emulate a signed integer C Overflow
unsigned int nOverflow = MAXINT;
nOverflow++;
printf("_CPUMathError:\"%s\"\nPress any key continue..",
	   pszResult[_CPUMathError()]);
fgetc(stdin);

// Emulate a signed integer C Underflow
nOverflow = -MAXINT;
nOverflow-=2;
printf("_CPUMathError:\"%s\"\nPress any key continue..",
	   pszResult[_CPUMathError()]);
fgetc(stdin);

   // Quit..
return 0;
}
//---------------------------------------------------------------------------
int _CPUMathError(void)
{
/*
	 CPUMathError by Directx (developed under Turbo C++ Explorer)
	 	nState:	 0 = No error, 1 = Overflow, 2 = Underflow
*/
int nState;

_asm
 {
	 jo 	_Overflowed// Is CPU Overflow/Underflow flag set?
	 mov nState,0	   // No!
	 jmp    _End	   

	 _Overflowed:	   // Do we have an Overflow or Underflow?
	  jns _Underflowed // If no sign the we have (?) Underflow
	  mov nState,1	   // else Overflow.
	  jmp _End

	 _Underflowed:	   // We should have underflow
	  mov nState,2

	 _End:			   // Complete!
 }

return nState;		   // Return state..
} 

 

Υ.Γ.

Disclaimer: Όλα αυτά μέσα από παρατηρήσεις και δοκιμές με τον CPU Disassembler/Debugger της CodeGear Turbo C++

Δημοσ.

οχι παιζουμε!ειδες τι σου ειναι οι ceidάδες?:mrgreen::mrgreen:

ευχαριστω πολυ να εισαι καλα.αλλη απορια

 

μιλοντας ομως για assembly δεν εχεις προβλημα μεταφερσιμοτητας του κωδικα?ειτε σε διαφορετικη αρχιτεκτονικη ειτε σε επεξεργαστες διαφορετικης οικογενειας?

Δημοσ.

Όπως είπα και προηγουμένως, assembly "εφόσον δεν μας ενδιαφέρει ιδιαίτερα το port του κώδικα σε διαφορετικά λειτουργικά ή επεξεργαστές".

:)

Δημοσ.
Όπως είπα και προηγουμένως, assembly "εφόσον δεν μας ενδιαφέρει ιδιαίτερα το port του κώδικα σε διαφορετικά λειτουργικά ή επεξεργαστές".

:)

ουπς!ναι,εχεις δικιο.ευχαριστω για αλλη μια φορα

Αρχειοθετημένο

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

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