größe unsigned int?
-
Hallo erstmal,
bin totaler Anfänger und bräuchte mal ein wenig hilfe
Ich versuche seit kurzem vergeblich rauszufinden welche größe eine Zahl in einem unsigned int erreichen kann. Hab gehört das das von Rechner zu Rechner unterschiedlich sein soll, also quasi nicht immer 4294967295.
Wäre für ein wenig hilfe sehr dankbar.mfg brgecko
-
Ein unsigned int geht von 0 bis mindestens 65535. Wie viel im Dorf vorgesehen ist, kann man so herausfinden:
#include <stdio.h> #include <limits.h> int main(void) { printf("von 0 bis %u", UINT_MAX); return 0; }
-
Danke schonmal
ich will das ganze mal etwas konkretisieren.
Ich habe vor eine Eingabe einer Zahl in ein unsigned int zu machen (in meinem fall jetzt unsigned int j), mit einem Hinweis das es nicht größer werden darf wie das was der Datentyp erlaubt und eine schleife um die Eingabeneu zu starten falls die Zahl Größer ist.
Nun soll das ganze aber (Schulaufgabe :)) unabhängig von der cpu funktionieren, sprich auf verschiedenen Rechnern kann der maximale Wert für das ui anders sein?Ich habe schon ein wenig mit sizeof() und ein wenig Rechnerei herumprobiert
unsigned int j, a; a = sizeof(j); printf("a: %d.\n",a); j=a; for(i=1;i<a;i++) { j=j*1024; printf("js: %d.\n",j); }
gibt dann bei mir
a: 4.
js: 4096.
js: 4194304.
js: 0.
raus, wo ich denke das im letzten schritt der Wert dem des Datentypes einfach überschritten hat und deshalb 0 rausgibt.PS.:
Nochmal danke für die Antwort.
Nicht das ich dich in frage stellen will aber ich tus trotzdem mal, sry :p
Wie groß ist der wert jetzt eigentlich standartmäßig?
Habe schon öfters beides gelesen 0-65535 und 0-4294967295
-
Standardmäßig ist der Wert mindestens 65535 (2^16 - 1). Das ist alles, was der Standard garantiert.
Es ist auf PCs heute üblich, int und unsigned int in 32-bit-Integer zu übersetzen, so dass dort in aller Regel bis zu 2^32 - 1 (knapp 4,3 Milliarden) in einen unsigned passt, aber im Standard garantiert ist das nicht. Auf Mikrocontrollern sind 16-bit-ints nicht ungewöhnlich, und mir ist zwar kein System bekannt, dass int als 64-bit-Integer auffasst, ich wäre aber nicht überrascht, wenn es so etwas schon gäbe oder es in nächster Zeit auftauchte.
-
brgecko schrieb:
Ich habe schon ein wenig mit sizeof() und ein wenig Rechnerei herumprobiert
unsigned int j, a; a = sizeof(j); printf("a: %d.\n",a); j=a; for(i=1;i<a;i++) { j=j*1024; printf("js: %d.\n",j); }
gibt dann bei mir
a: 4.
js: 4096.
js: 4194304.
js: 0.
raus, wo ich denke das im letzten schritt der Wert dem des Datentypes einfach überschritten hat und deshalb 0 rausgibt.PS.:
Nochmal danke für die Antwort.
Nicht das ich dich in frage stellen will aber ich tus trotzdem mal, sry :p
Wie groß ist der wert jetzt eigentlich standartmäßig?
Habe schon öfters beides gelesen 0-65535 und 0-4294967295Es gibt in der Hinsicht keinen Standard außer mind. 16 Bit äquivalent. Die limits findest Du meist in der <limits.h>, hab' mal was exemplarisch rausgegriffen.
Deine Rechnerei stimmt so sowieso nicht, mit (256 << sizeof(unsigned int)) -1 bist Du näher dran.Muß aber auch nicht stimmen, weil es durchaus 16- Bit chars gibt (ist halt die kleinste adressierbare Einheit).
Google mal nach Integer Overflow, da wirst Du die gängigen Methoden der Absicherung finden.
-
brgecko schrieb:
Ich habe vor eine Eingabe einer Zahl in ein unsigned int zu machen (in meinem fall jetzt unsigned int j), mit einem Hinweis das es nicht größer werden darf wie das was der Datentyp erlaubt und eine schleife um die Eingabeneu zu starten falls die Zahl Größer ist.
Das ist tricky. Mit scanf() geht das nicht, weil nicht definiert ist, was scanf() tun soll, wenn die Eingabe nicht im Ziel-Datentyp repräsentierbar ist. Das ist ärgerlich (scanf() ist überhaupt eher ärgerlich).
Das einzige, was mir dazu einfällt, ist, strtoul() zu verwenden. Das arbeitet zwar mit unsigned long's, kann aber dafür auf Überläufe achten. Etwa so:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <limits.h> #include <errno.h> int main(void) { unsigned long number; char buf[128], *start, *end; do { /* errno wird von strtoul() gesetzt, wenn ein Ueberlauf passiert. */ errno = 0; printf("eine Zahl von 0 bis %lu: ", ULONG_MAX); /* Eingabefehler abfangen. */ if (fgets(buf, sizeof buf, stdin) == NULL) return 1; /* Whitespace ueberlesen. */ for (start = end = buf; isspace(*start); start++) ; /* Falls negatives Vorzeichen vorhanden: alles nochmal. */ if (*start == '-') continue; number = strtoul(start, &end, 10); } /* Wiederholen solange weniger als 1 Zeichen umgewandelt wurde, oder ein Ueberlauf passiert ist. */ while (start == end || errno == ERANGE); printf("number ist %lu\n", number); return 0; }
So kann man auf sichere Weise ein unsigned long einlesen. Ein unsigned long ist mindestens so gross wie ein unsigned int, deshalb kann man dann bequem mit UINT_MAX vergleichen, und wenn number kleiner ist, kann man ein unsigned int daraus machen.
-
brgecko schrieb:
Wie groß ist der wert jetzt eigentlich standartmäßig?
Habe schon öfters beides gelesen 0-65535 und 0-4294967295Das ist eine leidige Frage. Heute hattest du das Glück, dass hier nur die Wahrheit steht (nämlich >=16 Bits). Das ist nicht überall und nicht immer so. Da hilft nur selbst nachschlagen, der Standard ist ISO/IEC 9899.
-
Vielen dank für die hilfe, bin am rumwerkeln
-
Moinsen, da bin ich wieder
Bin schon nen ganzen stück weiter gekommen wobei dein Programm bei dem Überlaufen funktionier meines aber nicht. Komm nicht drauf woran das liegen kann:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <limits.h> #include <errno.h> int main(){ //deklaration der variablen char text[11]; unsigned int j; unsigned char schalter; int i=0, laenge; //Schleifenanfang do { // errno wird von strtoul() gesetzt, wenn ein Ueberlauf passiert. errno = 0; schalter=0; printf("\nBitte geben Sie eine positive Zahl zwischen 0 und %u ein.\n", UINT_MAX); //Die Eingabe des Textes fgets(text, sizeof text, stdin); while (getchar() != '\n'); //Setzen der variable "laenge" für die Schleifen laenge=strlen(text); text[laenge]='\0'; //Schleifen zum entfernen allem was nicht Zahl ist for(i=0;i<laenge-1;i++) if(text[i]<'0' || text[i]>'9') { printf("Es dürfen nur positive ""Zahlen"" zwischen 0 und %u eingegeben werden!\n", UINT_MAX); schalter=1; break; } //Üertragen des Strings in das unsigned int j = strtoul(text, NULL, 10); } while (schalter == 1 || errno == ERANGE); printf("array: %s\n", text); printf("uint j: %u\n", j); return 0; }
Zahlen in dem grenzbereich funktioniert wunderbar, auch das abfangen von zeichen usw. das einzige was nicht läuft ist wenn der wert überläuft.
Dann gibt er mir das aus und stoppt das Programm:
array:
uint: 0
Woran liegts? strtoul sollte doch eigentlich errno auf ERANGE setzen und dann neu starten oder?btw. bin stolz wien keks das ich das schonmal so weit habe
-
hier mal was rauskommt wenn der wert überläuft:
Bitte geben Sie eine positive Zahl zwischen 0 und 4294967295 ein. 5555555555 Bitte geben Sie eine positive Zahl zwischen 0 und 4294967295 ein. Unsigned Integer: 0 Array:
wenn ich das errno in der schleife nicht auf 0 setzte dann funktioniert die schleife, das programm hängt aber in der schleife fest da errno ja immer ERANGE ist.
-
brgecko schrieb:
zeichen usw. das einzige was nicht läuft ist wenn der wert überläuft.
Dann gibt er mir das aus und stoppt das Programm:
array:
uint: 0
Woran liegts? strtoul sollte doch eigentlich errno auf ERANGE setzen und dann neu starten oder?Ja, strtoul gibt einen unsigned long aus, aber j ist unsigned int. Wäre eine mögliche Fehlerquelle, daß errno nicht klick macht. Kommt aber drauf an, wie Dein Compiler das handhabt. Bei meinem Liebligscompiler sind unsigned und unsigned long z.B. beide auf 32 Bit.
Eine etwas ketzerische Variante wäre, das in einen double einzulesen, mit UINT_MAX zu vergleichen und dann erst ggf. nach uint zu casten.
-
Wenn du so unsicher bist, warum pruefst du den eingelesenen String nicht direkt, ob er nur aus Ziffern besteht und lexikographisch kleiner als "4294967296" ist. Danach kannst du beruhigt umwandeln.
-
Ok, hab mein programm vorgetragen. Habs mit dem double und vergleich mit uint_max gemacht und die schleife rausgehauen.
Es war super super hässlich aber es hat funktioniert.
Vielen vielen dank nochmal für die ganze hilfe
-
Die Aufgabe war ja gerade dazu da, die Datentypen von C (und deren Beschränkungen)etwas besser kennenzulernen. Man könnte sich eine Tabelle mit Konstanten (8,16,32,64,128,256,512bit-maximalwert erstellen und bestimmten Datentypen zuweisen (oder maximalen Eingabewiederholungen).
Mit dem sizeof-Operator kann man sich die Anzahl der Bytes anzeigen lassen, welche ein Datentyp braucht, oder hergibt.
Mit z.B. getchar läßt sich das Eingabemuster kontrollieren.
Um den Wert FF FF FF FFh auf Überschreitung zu überprüfen, muß man wissen, was passiert, wenn der Grenzwert überschritten wird oder und wie sich eine Überschreitung prüfen lässt, wenn die Maschinenregister nicht weiter als Grenzwert können.Letztlich kann "Cpu-unabhängig" nur heißen: Mit FPU, GPU oder kleinen
Integerwerten "zu Fuß" rechnen.
-
pointercrash() schrieb:
Eine etwas ketzerische Variante wäre, das in einen double einzulesen, mit UINT_MAX zu vergleichen und dann erst ggf. nach uint zu casten.
Nicht ketzerisch, sondern einfach nicht portabel. Nehmen wir an, ein System legt ein 'int' auf 64 Bits Breite fest und verwendet IEEE 754. Dann bekommt das Verfahren Probleme mit manchen int's, die mehr Stellen haben als DBL_DIG. In dem Fall zum Beispiel mit 2^64 - 1 = 18446744073709551615.
Mit Systemen, die kleinere int's verwenden, kann man uint64_t nehmen:
#include <stdio.h> #include <stdint.h> // System-abhängiger Formatstring für uint64_t #define FMT "%llu" int main(void) { uint64_t ulong_var; double double_var; /* einen uint64_t über double einlesen */ sscanf("18446744073709551615", "%lf", &double_var); printf("double -> %lf\n", double_var); ulong_var = double_var; printf("uint64_t -> " FMT "\n\n", ulong_var); /* einen uint64_t direkt einlesen */ sscanf("18446744073709551615", FMT, &ulong_var); printf("uint64_t -> " FMT "\n", ulong_var); return 0; }
Das gibt hier aus:
double -> 18446744073709551616.000000 uint64_t -> 0 uint64_t -> 18446744073709551615
Hier sollte man direkt lesen, was aber auch nicht geht, weil nicht definiert ist, was scanf() mit einer grösseren Eingabezahl tun wird. Ähnliches gilt für alle Ganzzahltypen, weil jeder davon genauso breit wie ein IEEE-double sein darf.
-
Auch wenns etwas dirty ist, aber mir ist aufgefallen, dass man bei unsigned int auch einfach -1 zuweisen kann, was dann dem MAX Wert entspricht da der hex code dann ja entsprechend, max ist, also 0xFFFFFFFF oder so... +-1 Werteinheit. Entspricht zwar nicht dem, wie mans machen sollte, aber nur um mal "nachzuschauen" sollte das ja legetim sein. Für Programme, die das während der Laufzeit brauchen, sind die Limits zu empfehlen.
Sorry wenn da jetzt was schon erwähnt worden war, hab das nur überflogen, das Thema und da war mir das spontan eingefallen.