Hallo mir ist aufgefallen, dass zwei fast gleiche Befehle zwei völlig unterschiedliche Ergebnisse liefern nämlich folgendes: printf("\n\nOhne Berechnung: %ld",100000); printf("\nDurch Berechnung: %ld",(100*1000) ); Ohne die Berechnung wird mir dadurch 100000 angezeigt, jedoch als Produkt aus 100 und 1000 erhalte ich -2036300128. Weiß jemand wie das kann? Gruß Marcel
Peter Dannegger schrieb: > Ja, jedes C-Buch (Zahlenformate). Wenn es denn so einfach wäre :-) Ohne Berechnung: 100000 Durch Berechnung: 100000 "d:\temp\lcc\test.exe" Return code 25 Execution time 0.016 seconds Press any key to continue... Es hängt schon vom Compiler ab...
Georg G. schrieb: > Peter Dannegger schrieb: >> Ja, jedes C-Buch (Zahlenformate). > > Wenn es denn so einfach wäre :-) Ist es. Auch Zahlen haben einen Datentyp. 100 ist ein int 1000 ist ein int also hat das Ergebnis von 100*1000 welchen Datentyp? Und wie passt der zu %ld? Interessanter wird es bei 100000. Denn da ist tatsächlich erst mal nicht klar, ob das ein int oder ein long ist. Das hängt dann tatsächlich vom Compiler (bzw. der darunterliegenden Hardware) ab. Aber das sind Basisdinge, die man als C-Programmierer sowieso immer wissen muss: wie groß ist ein int und über welchen Zahlenbereich erstreckt er sich?
Karl Heinz Buchegger schrieb: > also hat das Ergebnis von 100*1000 welchen Datentyp? > Und wie passt der zu %ld? %ld habe ich gewählt da %d ja nur einen Bereich von -32768 ... +32767 bzw %u von 0 bis +65535 hat. Und als Compiler habe ich den vom Wickenhäuser.
Marcel W. schrieb: > Karl Heinz Buchegger schrieb: >> also hat das Ergebnis von 100*1000 welchen Datentyp? >> Und wie passt der zu %ld? > > %ld habe ich gewählt da %d ja nur einen Bereich von -32768 ... +32767 > bzw %u von 0 bis +65535 hat. Du kannst daber nicht einfach irgendein Ausgabeformat wählen! Das muss schon zu dem passen, was du der Funktion als Argument gibst! nicht %d hat einen Ausgabebereich von -32768..+32767 sondern ein int kann nur Werte in diesem Bereich annehmen. Daher nochmal die Frage: 100 ist ein int 1000 ist ein int Welchen Datentyp hat daher das Ergebnis von 100*1000? (und wie groß kann es daher in Zahlenform maximal werden?) Die Frage und deren Beantwortung ist WICHTIG! Denn erst dann hast du eines der wesentlichen fundamentalen Zusammenhänge in der Analyse von arithmetischen Ausdrücken entwickelt, wenn du diese Frage korrekt beantworten kannst!
Es gibt Gerüchte, wonach der Typ "Integer" nicht auf allen Maschinen 16 Bit breit ist. Bei manchen Compilern ist er 32 Bit breit. Damit passt 100000 auch in ein Integer und den kleine Fehler mit dem "l oder nicht l" verzeiht der Compiler, vielleicht sogar ohne Warnung (die der gute Programmierer ohnehin abstellt, denn er weiß alles besser).
Bitte Georg. Wir reden hier von einem 8051, einem 8-Bit µC. Es ist nicht zielführend, wenn du den Fragesteller jetzt auch noch mit Spitzfindigkeiten zusätzlich verwirrst.
Karl Heinz Buchegger schrieb: > 100 ist ein int > 1000 ist ein int > > Welchen Datentyp hat daher das Ergebnis von 100*1000? > (und wie groß kann es daher in Zahlenform maximal werden?) Demnach würde ich sagen ist das Ergebnis auch ein int und kann maximal +65535 annehmen?
Marcel W. schrieb: > Karl Heinz Buchegger schrieb: > >> 100 ist ein int >> 1000 ist ein int >> >> Welchen Datentyp hat daher das Ergebnis von 100*1000? >> (und wie groß kann es daher in Zahlenform maximal werden?) > > > Demnach würde ich sagen ist das Ergebnis auch ein int und kann maximal Bingo! > +65535 annehmen? Aber: dein Ergebnis wird nicht 32768 sein, sondern da passiert ein Überlauf. D.h. da kommt irgendwas raus. Aber es ist ein int! Und daher muss die Formatieranweisung in printf auch ein %d sein. Denn %d ist für einen int. printf("\nDurch Berechnung: %d",(100*1000) ); Damit passen Berechnung und Formatieranweisung erst mal in den Datentypen zusammen. Aber: wir wissen, dass 100*1000 als int-Ergebnis nicht korrekt sein wird, weil das Ergebnis überläuft. 100000 ist nun mal zu groß für einen 16-Bit int. Also muss man dafür sorgen, dass die Berechnung eben nicht als int Berechnung gemacht wird, sondern als long Berechnung. Denn ein (32-Bit) long kann dieses Ergebnis aufnehmen. Und wie machen wir das?
Ordentliche Compiler meckern zum einen gleich (s.u.) und machen aus (100*1000) eh gleich die Kostante 100000. klaus@LittlX:~/src$ cat berechnung.c int main(void) { printf("\n\nOhne Berechnung: %ld",100000); printf("\nDurch Berechnung: %ld\n",(100*1000) ); } klaus@LittlX:~/src$ gcc berechnung.c berechnung.c: In Funktion »main«: berechnung.c:3:3: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »printf« [standardmäßig aktiviert] berechnung.c:3:3: Warnung: Format »%ld« erwartet Argumenttyp »long int«, aber Argument 2 hat Typ »int« [-Wformat] berechnung.c:4:3: Warnung: Format »%ld« erwartet Argumenttyp »long int«, aber Argument 2 hat Typ »int« [-Wformat] klaus@LittlX:~/src$ ./a.out Ohne Berechnung: 100000 Durch Berechnung: 100000 klaus@LittlX:~/src$ gcc berechnung.c -S [...] klaus@LittlX:~/src$ cat berechnung.s .file "berechnung.c" .section .rodata .LC0: .string "\n\nOhne Berechnung: %ld" .LC1: .string "\nDurch Berechnung: %ld\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 andl $-16, %esp subl $16, %esp movl $100000, 4(%esp) movl $.LC0, (%esp) call printf movl $100000, 4(%esp) movl $.LC1, (%esp) call printf leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3" .section .note.GNU-stack,"",@progbits klaus@LittlX:~/src$ [Interessanter Weise meckert der arm-gcc nicht!] klaus@LittlX:~/src$ arm-none-eabi-gcc berechnung.c -S berechnung.c: In function 'main': berechnung.c:3:3: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default] klaus@LittlX:~/src$ cat berechnung.s .cpu arm7tdmi .fpu softvfp .eabi_attribute 20, 1 .eabi_attribute 21, 1 .eabi_attribute 23, 3 .eabi_attribute 24, 1 .eabi_attribute 25, 1 .eabi_attribute 26, 1 .eabi_attribute 30, 6 .eabi_attribute 34, 0 .eabi_attribute 18, 4 .file "berechnung.c" .section .rodata .align 2 .LC0: .ascii "\012\012Ohne Berechnung: %ld\000" .align 2 .LC1: .ascii "\012Durch Berechnung: %ld\012\000" .text .align 2 .global main .type main, %function main: @ Function supports interworking. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 1, uses_anonymous_args = 0 stmfd sp!, {fp, lr} add fp, sp, #4 ldr r0, .L2 ldr r1, .L2+4 bl printf ldr r0, .L2+8 ldr r1, .L2+4 bl printf mov r0, r3 sub sp, fp, #4 ldmfd sp!, {fp, lr} bx lr .L3: .align 2 .L2: .word .LC0 .word 100000 .word .LC1 .size main, .-main .ident "GCC: (GNU Tools for ARM Embedded Processors) 4.6.2 20120613 (release) [ARM/embedded-4_6-branch revision 188521]" klaus@LittlX:~/src$
klausr schrieb: > Ordentliche Compiler meckern zum einen gleich (s.u.) das ist ok. > und machen aus > (100*1000) eh gleich die Kostante 100000. Wenn SEIN Compiler das macht, dann ist er fehlerhaft
Karl Heinz Buchegger schrieb: > Wenn SEIN Compiler das macht, dann ist er fehlerhaft Ja... ich hatte das 8051 im Titel überlesen!
Karl Heinz Buchegger schrieb: > Also muss man dafür sorgen, dass die Berechnung eben nicht als int > Berechnung gemacht wird, sondern als long Berechnung. Denn ein (32-Bit) > long kann dieses Ergebnis aufnehmen. > > Und wie machen wir das? Ich bin davon ausgegangen, dass so eine Art Autocast vorgenommen werden würde :D aber da dies anscheinend nicht der Fall ist muss die Lösung lauten: printf("\n\nOhne Berechnung: %ld",100000); printf("\nDurch Berechnung: %ld",(long)100*(long)1000 ); Vielen dank, damit wäre mein Problem gelöst. Gruß Marcel
Marcel W. schrieb: > Karl Heinz Buchegger schrieb: >> Also muss man dafür sorgen, dass die Berechnung eben nicht als int >> Berechnung gemacht wird, sondern als long Berechnung. Denn ein (32-Bit) >> long kann dieses Ergebnis aufnehmen. >> >> Und wie machen wir das? > > Ich bin davon ausgegangen, dass so eine Art Autocast vorgenommen werden > würde :D Du bist falsch ausgegangen. Und spätestens jetzt ist der Punkt für meinen Standardspruch erreicht: Du brauchst ein vernünftiges Buch! Denn #das# war noch vergleichsweise einfach!
Wenn du auf dem 8051 einen printf() verwendest, dann verwende ihn am besten nur, wenn du das "Hello WORLD Programm" machst, und sonst nichts. Sonst nimm lieber low level Routinen zu Umwandlungen und Eingaben Ausgaben aller Art. Ich hab natürlich leicht reden, habe FIFOs seriell und skalierbare Rechenroutinen sogar in Assembler eingebunden separat, was ich in der Vergangenheit alles mal erstellte. Z.B. BIN-BCD mehrstellig, und optimiert schnellstens. Um eine Zahl auszugeben, schreibe ich dann den Funktionsaufruf: print_bin_bcd(argument). Das geht ins FIFO, wird nicht online direkt ausgegeben, um den µC zu blockieren.
Wilhelm Ferkes schrieb: > Wenn du auf dem 8051 einen printf() verwendest, dann verwende ihn am > besten nur, wenn du das "Hello WORLD Programm" machst, und sonst nichts. Warum denn das? Ohne Speicher- und Laufzeitprobleme gehen printf() und Co. problemlos. Die Zeiten der Asm-Bit-Speichergeizerei ist vorbei!
32MHz/32kB/4kB schrieb: > Wilhelm Ferkes schrieb: >> Wenn du auf dem 8051 einen printf() verwendest, dann verwende ihn am >> besten nur, wenn du das "Hello WORLD Programm" machst, und sonst nichts. > > Warum denn das? Ohne Speicher- und Laufzeitprobleme gehen printf() und > Co. problemlos. > > Die Zeiten der Asm-Bit-Speichergeizerei ist vorbei! Halb richtig, oder völlig falsch. Die printf()-Funktion steckt so lange fest, bis sie z.B. von einem Interrupt unterbrochen wird. Sonst weiter nichts.
Wenn man nicht gerade nen mini 8051 mit 2kB Flash nimmt, kann man durchaus printf einsetzen. Und die Laufzeit spielt auch keine Rolle, wenn es für die Anzeige ist, so schnell kann kein Mensch ablesen. Und auch die float Libs sind nicht so schlecht, daß man davor gleich Angst haben muß. Nur für superschnelle Regelkreise ist float vielleicht nicht die beste Wahl. Ein 8051 mit 32kB, 64kB oder 128kB Flash ist kein Thema mehr. Und XTAL/12 wird oftmals auch nicht mehr geteilt. Peter
Es kommt drauf an. 9600 Baud sind 9600 Baud, auch wenn der µC mit 200MHz rennt. Wenn man da nicht selbst die Libraries umbaut, dann steckt ein printf() eben mit den 9600 Baud und Polling so lange an seiner Stelle fest, bis auch das letzte Zeichen ausgegeben ist.
Das liegt dann aber nicht am printf, sondern am putchar. Schreib für das putchar nen FIFO und die Sache ist gegessen. Peter
Peter Dannegger schrieb: > Das liegt dann aber nicht am printf, sondern am putchar. Schreib für das > putchar nen FIFO und die Sache ist gegessen. > > Peter Ja sicher. Ich weiß es ja. Man muß auch FIFOs in die serielle Schnittstelle implementieren, wo putchar hinein schreibt. Manche Compiler liefern es mit, andere nicht. SDCC beispielsweise hat es. Aber wenn man einen Compiler nach der Installation als Ahnungsloser mit printf() einfach mal so benutzt, ist es eben tödlich. Da kann man Pech haben, daß eben putchar nicht in ein FIFO schreibt, und bei jedem Byte das Transmit-Flag abgewartet wird. In meiner Studentenzeit liefen die Jungs aber reihenweise auf, und wunderten sich, daß ihr Programm außer printf() nicht mehr viel machte. Ein Professor warnte auch davor, in einem schnellen Programm printf() anzuwenden. OK, für die Rechnerei innerhalb des printf() sind die µC heute reichlich schnell.
Wilhelm Ferkes schrieb: > Aber wenn man einen Compiler nach der Installation als Ahnungsloser mit > printf() einfach mal so benutzt, ist es eben tödlich. Da kann man Pech > haben, daß eben putchar nicht in ein FIFO schreibt, und bei jedem Byte > das Transmit-Flag abgewartet wird. > > In meiner Studentenzeit liefen die Jungs aber reihenweise auf, und > wunderten sich, daß ihr Programm außer printf() nicht mehr viel machte. > Ein Professor warnte auch davor, in einem schnellen Programm printf() > anzuwenden. Die gute alte Zeit ist schon lange vorbei. Und Profs nur Theoretiker. ;-P Bei µCs muss putchar() sowieso an die eigene Hardware angepasst werden. Das war gestern so und ist noch heute so. Peter Dannegger schrieb: > Ein 8051 mit 32kB, 64kB oder 128kB Flash ist kein Thema mehr. Und > XTAL/12 wird oftmals auch nicht mehr geteilt. Ja, bei 8051 denken immer alle an einen 40 poligen DIL Riesen mit externen Speichern und 11,... MHz Quarz. :-(
32MHz/32kB/4kB schrieb: > Bei µCs muss putchar() sowieso an die eigene Hardware angepasst werden. > Das war gestern so und ist noch heute so. Aber das weiß man erst, wenn man mal mit der Schnauze gegen die Wand lief, und stark wieder abprallte. Anfänger eher nicht. An der FH gab es dazu auch nicht den geringsten Ton.
Wilhelm Ferkes schrieb: >> Bei µCs muss putchar() sowieso an die eigene Hardware angepasst werden. >> Das war gestern so und ist noch heute so. > > Aber das weiß man erst, wenn man mal mit der Schnauze gegen die Wand > lief, und stark wieder abprallte. Nö, das gilt immer und für jeden. Woher weiss der Compiler Hersteller wohin dein putchar() sendet? LCD, SPI, I2C, RS232, ..., ... Da muss man immer selber ran. Denn sie wissen nicht was sie tun gibt es im Kino und nicht in der Entwicklung. ;-P
Georg G. (df2au) schrieb: > Es gibt Gerüchte, wonach der Typ "Integer" nicht auf allen Maschinen 16 > Bit breit ist. Bei manchen Compilern ist er 32 Bit breit. Damit passt > 100000 auch in ein Integer und den kleine Fehler mit dem "l oder nicht > l" verzeiht der Compiler, vielleicht sogar ohne Warnung (die der gute > Programmierer ohnehin abstellt, denn er weiß alles besser). Karl Heinz Buchegger (kbuchegg) (Moderator) konterte > Bitte Georg. > Wir reden hier von einem 8051, einem 8-Bit µC. > Es ist nicht zielführend, wenn du den Fragesteller jetzt auch noch mit > Spitzfindigkeiten zusätzlich verwirrst. Man könnte dazu anmerken, wenn der int-Typ 32-bit umfasst stellt sich das Problem mit printf auch wieder, wenn die Zahlen dort dann nicht mehr hineinpassen. Siehe Anhang. Einmal mit und ohne expliziter Typumwandlung nach 64-bit signed int. PC halt, aber das gleiche Problem. Also nix mit "impliziter Umwandlung".
Proxxon schrieb: > Man könnte dazu anmerken, wenn der int-Typ 32-bit umfasst stellt sich > das Problem mit printf auch wieder auf einem 8Bit 8051??? Bitte nenne den Compiler.
c90 (Gast) schrieb: Proxxon schrieb: >> Man könnte dazu anmerken, wenn der int-Typ 32-bit umfasst stellt sich >> das Problem mit printf auch wieder > auf einem 8Bit 8051??? Nö. > Bitte nenne den Compiler. Pelles C und das Beispiel bezog sich nicht auf µC. Ging aber auch aus dem Text hevor. "PC halt, .."
Proxxon schrieb: > das Beispiel bezog sich nicht auf µC Wirf mal einen Blick auf den Titel: "8051er Ausgabeproblem" Für mich ist der 8051 ein µC und kein PC, aber man lernt ja nie aus :-(
> Wirf mal einen Blick auf den Titel:
Hättest du mal besser mein Posting richtig gelesen ..
Im übrigen war das Threadthema längst durch, was man unschwer an den
nicht mehr getätigten Wortbeiträgen erkennen kann. Deshalb hast du hier
ein sinnloses Palaver losgetreten. Aber wenn du möchtest darfst du dich
gerne weiter daran abarbeiten. Viel Spass!
Da der Thread sowieso durch ist, kann ich ihn auch noch schänden: Für die korrekte Verwendung von printf, fprintf und sprintf muss man bei jeder Quelltext-Änderung feststellen, wie lang der Ergebnisstring maximal werden kann, und das mit der Länge des Puffers vergleichen, die in der jeweiligen stdlib benutzt wird. Das kann besonders bei Verwendung des Formats "%s" recht aufwendig und fehlerhaft werden, und wenn irgendwelche Strings von "außen" kommen, sind "if (strlen(..." -Anweisungen unumgänglich. Auch wenn printf sehr kompfortabel in der Anwendung scheint, so kann seine Verwendung in Einzelfällen so gefährlich sein, dass man lieber ganz darauf verzichtet, und den Code, der die Daten in lesbare Form bringt, für jeden Parameter selbst aufruft. Da gewöhnt man sich schnell dran, und vermisst printf bald gar nicht mehr. Ähnliches gilt für scanf, strcpy, strcat, etc.. Diese ganzen Funktionen sind wie Stützräder am Fahrrad. - Für den Anfang hilfreich, aber wenn man sie nicht rechtzeitig ablegt, haut man sich damit irgendwann in der Kurve auf die Fresse.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.