C Sind die Ausgabeformatierungen auf jedem System / Compiler anders?

Stannis

Lieutenant
Registriert
Juli 2011
Beiträge
549
Gemäß diesem Wikibook sollten das die Formatierungen für scanf und printf sein. So weit so wundervoll.

Warum ist das bei mir (Ubuntu, gcc) anders?

Ich will Wurzeln ziehen, habe zuerst mit floats und der Formatierung %f gearbeitet, alles wunderbar. Dann wollte ich auf double, der Genauigkeit wegen, umsteigen.

%f, %e und nichts aus diesem Wikibook funktioniert, bis Ich mir %lf (long float) ausgedacht habe, was funktioniert hat.

%e und %f scheinen auch noch beide für float zuständig zu sein :freak:

Woher weiß Ich denn überhaupt, was Sache ist, wo finde Ich eine richtige Liste? Bei long double ists vermutlich wieder was anderes.

Hängt das damit zusammen, dass die Speichergrößen für Variablen (32 oder 64 usw. Bit) auf allen Systemen anders sein können?

Code:
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%f", &eingabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%d", &eingabe);
  ^
wurzel.c:11:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
  printf("%d", ausgabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%f", &eingabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%e’ expects argument of type ‘float *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%e", &eingabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%f", &eingabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
wurzel.c: In function ‘main’:
wurzel.c:9:2: warning: format ‘%ld’ expects argument of type ‘long int *’, but argument 2 has type ‘double *’ [-Wformat=]
  scanf("%ld", &eingabe);
  ^
wurzel.c:11:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘double’ [-Wformat=]
  printf("%ld", ausgabe);
  ^
imperator@imperator-PC:~/Programmieren/C$ gcc wurzel.c 
imperator@imperator-PC:~/Programmieren/C$ ./a.out 
Quadratwurzel aus (>1): 101
10.049876
 
Hmm, ok...
Sowas könnten die ruhig ins Handbuch schreiben :/

Darum, dass Variablen immer mal unterschiedlich groß sein können (je nach System), brauche Ich mich als Programmierer aber nicht zu scheren, ja? Das macht der Compilter automatisch.
Wobei mich mal interessieren würde, wie ein 64-Bit-Prozessor 128-Bit-long-doubles handhabt.
 
Wenns C sein muss dann hier:
http://stackoverflow.com/questions/1546510/declaring-fixed-size-integer-typedef-in-standard-c
Oder halt hier:
http://www.cplusplus.com/reference/cstdint/

Wobei mich mal interessieren würde, wie ein 64-Bit-Prozessor 128-Bit-long-doubles handhabt.
Naja mit Überlauf und mehr als 1 Takt im Notfall.
Früher hatten PCs(Konsolen ja auch weniger bit und konnten schon über 16bit Zählen.
Außerdem gibts so sachen wie 'bigint' die dynamisch mitwachsen.
 
Bei Integern ist das trivial, aber es ging ja um Gleitkommazahlen. Und da muss da quasi eine komplette FPU in Software emuliert werden, inklusive Rounding und solchen Späßen - dass das zwangsweise arschlangsam ist, muss ich hoffentlich niemandem erzählen.
 
long doubles sind aber nicht unbedingt 128 Bit breit. Auf x86/x64 Systemen sind es normalerweise 80 bit und das können die Prozessoren schon seit dem 486er Zeiten in HW berechnen. Microsofts compiler macht daraus sogar normale double (64Bit) Zahlen
 
Ich glaube, das weiß der TE. Aber wenn man es macht, dann eben emuliert.

Und die 80 Bit-Dinger brauchen zwingend x87-Befehle, die sind nicht vektorisierbar, kaum parallelisierbar (stack-basierte FPUs sind ja auch so eine gute Idee) und damit so unglaublich langsam, dass man da fast genau so gut 128 Bit-Festkommawerte einsetzen kann, falls es das Anwendungsgebiet erlaubt. Da hat man mit etwas Glück sogar genaueren Ergebnisse.
 
Zuletzt bearbeitet:
VikingGe schrieb:
Bei Integern ist das trivial, aber es ging ja um Gleitkommazahlen. Und da muss da quasi eine komplette FPU in Software emuliert werden, inklusive Rounding und solchen Späßen - dass das zwangsweise arschlangsam ist, muss ich hoffentlich niemandem erzählen.

Wenn es aber für einen Anwendungsfall benötigt wird, wie z.B. in wissenschaftl. Simulationen, muss man eben darauf zurückgreifen. Und dann ist es eben auch so, dass in x86_64 nicht alle Randfälle des IEEE 754 Standards korrekt abgedeckt implementiert sind weil dies einfach deutlich mehr Chipfläche benötigen würde bzw. die Operationen langsamer machen würde.

Und die Frage ist ja auch noch wie man "arschlahm" definiert. Langsamer als die vom Prozessor angebotenen Operationen? Definitiv! Geeignet für Number Crunching? Absolut nicht! Für normale Anwendungsfälle schnell genug? Auf jedenfall!
 
Und wo finde Ich die Formatierungen für unsigned floats, doubles usw.?
 
Schnitzelsemmel schrieb:
Und wo finde Ich die Formatierungen für unsigned floats, doubles usw.?

Die gingen bei einer Hackerparty mit Stripperinnen im MIT im Jahre 1972 verloren, seitdem hat die keiner mehr gefunden ...
 
LOL :D Was blöderidiot damit sagen wollte ist, es GIBT KEINE unsigned float / double Typen (in C).
 
Oh, tja :p
Also der Autor dieses Handbuches ist anderer Meinung (siehe Link).
Außerdem kann Ich sie fehlerfrei definieren.
 
@Schnitzelsemmel: Da würde mich jetzt mal interessieren, was du für einen Compiler nutzt. Standardkonform ist das ganz sicher nicht und spricht nicht unbedingt für die Qualität dieses Onlinetutorials/buchs.
 
Zuletzt bearbeitet:
Ich nutze die gcc. Aber Kommando zurück, im Eifer des Gefechts hab Ich das wohl ein wenig falsch erkannt, unsigned floats mag er tatsächlich nicht. Anspruchsvoller Codehaufen :0

Das ist das beste Tutorial, das mir bisher vor die Flinte gelaufen ist. Dieses wikibook, das Ich weiter oben verlinkt habe, ist noch schlechter (mMn).
 
Naja, mein üblicher Ratschlag ist ja erst garnicht C zu lernen, wenn mans nicht unbedingt braucht.
Aber so oder so: wenn das Tutorial verständlich und interessant aufgebaut ist, dann ist das erstmal wichtiger als das letzte bisschen Genauigkeit.
 
Das ist ja geradezu entsetzliche Ketzerei. C ist die heilige, erwählte Sprache der ehrwürdigen Wissenschaft der Elektrotechnik :heilig:
 
Und wenn du dieser ehrwürdigen Wissenschaft angehörst bleibt dir auch nix anderes übrig.

Aber ich persönlich fange langsam an C als eine art assembler code zu betrachten. Sollte man gesehen haben, manchmal muss man es nutzen, aber für fast alles, was nicht direkt mit der HW kommuniziert gibt's besseres (das einem im Zweifelsfall C-Code generiert)
 
Ich bin "vom Fach", ja. Ich mag die Sprache bisher recht gerne.
C war ja auch Anfangs als eine Art Super-assembler gedacht ;)
Du willst vermutlich darauf hinaus, dass es für anwendungsorientierten Kram wie die Softwareentwicklung bequemere und einfachere Sprachen gibt, die z.B. objektorientiert sind?
Ich denke C wird dauerhaft sein Plätzchen haben, viele Betriebssysteme werden ja darin geschrieben.


Hat nebenbei noch jemand Lust, mir zu sagen, warum mein bösartiges Primzahlprogramm zwischen Zeile 20 und 22 meine Nutzereingabe, ob Ich die Zahlen auch ausgeben lassen will, schlichtweg ignoriert?
Klappt alles wunderbar, nur die Ausgabe-Funktion lässt er mich mit dieser Abfrage nicht durchführen...
Code:
// Laufzeit bis 1 Mio deutlich unter 1s (~ 0,85 s) ; berechnte Prims: 78498

#include <stdio.h>
#include <stdlib.h>

int* feldgen(int grenze);
int* primgen(int grenze, int *bote, int *feld);
void ausgabe(int *prims, int anz);

int main(){
	int anz=2, grenze;		// grenze = eingabe & automatische sinnvolle Laufgrenzermittlung; anz = anzahl der prims 
	int *prims, *bote=&anz;		// Bote, um Anzahl der Primzahlen für Ausgabe zu erhalten
	char ausg;			// für Ausgabeoption
	
	printf("Grenze: ");
	scanf("%d", &grenze);

	grenze = grenze/2+1;		// höchstens ~ die Hälfte aller (ungeraden) Zahlen könnten prim sein
	prims = primgen(grenze, bote, feldgen(grenze));
	printf("Anzahl der Primzahlen: %d\nPrimzahlen auflisten? [j / n]: ", anz);
	ausg = getchar();
	if(ausg=='j') ausgabe(prims, anz);
	printf("\n");
	free(prims);
	return 0;
}

void ausgabe(int *prims, int anz){
	int i, j=0, k=10;
	
	for(i=0; i<anz; i++){
		printf("%d ", prims[i]);
		j++;
		if(prims[i+1] > k){
			printf("\n\n");
			k *= 10;
			j=0;
		}
		
		if(j==20){
			printf("\n");
			j=0;
		}
	} 
}
			

int* feldgen(int grenze){
	int ungeradeZahl=3, i;
	int *feld;
	
	feld = (int*)calloc(grenze, sizeof(int));
	feld[0] = 2;
	
	for(i=1; i<grenze-1; i++){
		feld[i] = ungeradeZahl;
		ungeradeZahl += 2;
	}
	
	return feld;
}

int* primgen(int grenze, int *bote, int *feld){
	int retter=2, teiler=3;
// retter = Schutz vor Selbstausnullung, teiler = Überprüfungsteiler, start = primzahl 3; anzahl = Anzahl der prims beim Programmstart
	int i, j, k=1;	// k entspricht "Raster-koordinaten-zahl"
	grenze--;	// Wir beginnen bei 0 zu zählen :)
//--------------------------------------------------------------
	for(i=0; i<grenze; i++){
		j=1;
		
		while( (k+j*feld[k]) < grenze){
			feld[k+j*feld[k]] = 0;
			j++;
		}
		
		for(j=retter; j<grenze; j++){
			if(feld[j] != 0){		// Setzung des Teilers auf die nächste Primzahl
				*bote += 1;		// Erhöhung der Anzahl der Primzahlen
				k = j;
				retter = j+1;		// Erhöhen der Schutzvariable, um die neue Primzahl/Teiler vor Selbstausnullung zu schützen
				break;			// Verlassen der Schleife, da neuer Teiler (k) gefunden wurde
			}
		}
	}
//--------------------------------------------------------------
	int *prim;
	j=0;

	prim = (int*)calloc(*bote, sizeof(int));
	
	for(i=0; i<grenze; i++){
		if(feld[i] != 0){
			prim[j] = feld[i];
			j++;			// Hilfsvariable k, um das neue Array geordnet von vorn nach hinten zu füllen
		}
	}

	free(feld);
	return prim;
}
 
gnah, dass es diesen Puffer gibt, wusste Ich.
Dachte, das sei kein Problem, wenn Ich zwischen den Eingaben andere Aufgaben (Funktionen) ausführe... immerhin sollte er bei getchar pausieren und auf die Eingabe warten. Im Puffer wird schließlich immer irgendetwas gespeichert sein, das kann er doch nicht einfach weiterverwenden...
 
Zurück
Oben