Holger schrieb:> Warum wird bei *j++ die Adresse erhöht und nicht der Inhalt der> Speicherstelle?
(*j)++;
Adresse um 4 erhöhen weil dein int 4 byte gross ist und +1 zum nächsten
int führen soll (den es hier nicht gibt).
Holger schrieb:> (*j)++;> getestet und funktioniert.
Am besten gewöhnst du dir unnötig klammernsparende Schreibweisen gar
nicht erst an. Wenn du nicht tagtäglich immer nur programmierst,
unterlaufen dir sonst leicht mal Fehler. Oder du verlierst Zeit, weil du
beim Suchen von (anderen) Fehlern immer wieder mal
überlegen/nachschlagen musst, ob nicht diese Schreibweise der gesuchte
Fehler ist.
Stichwort: Defensive Codierung.
Der Compiler übersetzt ohnehin unabhängig von der Schreibweise, es spart
also nichts.
Holger schrieb:> i = *j; // i ist irgendwas ok
Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken,
z.B. Programmabsturz. Oder der Compiler entfernt einfach die
main()-Funktion komplett, weil er davon ausgehen darf dass UB nie
auftritt und somit die main() Funktion sowieso nie aufgerufen wird, weil
sie immer zu UB führt. Das gilt auch für Lesezugriffe.
Niklas G. schrieb:> Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken,> z.B. Programmabsturz.
Aber nur im Kontext der von Dir nicht zitierten vorangegangenen
Codezeilen.
Für sich alleine betrachtet ist die von Dir zitierte Zeile 8 vollkommen
legitimer Code, nämlich 'ne simple Pointerdereferenzierung.
"Kriminell" wird es durch die Zeilen 6 und 7 des Codes aus dem
Eröffnungsthread, die den Pointer auf etwas anderes zeigen lassen als
beim Aufruf der Funktion, der der Pointer übergeben wurde.
j++; // adresse +4 ok
Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.
Wir programmieren SPSen in ANSI C und da ist INT nur 2 byte groß.
Georg W. schrieb:> Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.
Ist es auch nicht.
Man kann es getrost als Fehler betrachten, hier "generell" anzunehmen.
Auf 8- oder 16-Bit-Systemen ist ein int üblicherweise 16 Bit groß, auf
32-Bit-Systemen ist er üblicherweise 32 Bit groß, auf 64-Bit-Systemen
ist er meistens auch 32 Bit groß, kann aber auch 64 Bit groß sein.
Georg W. schrieb:> Wir programmieren SPSen in ANSI C und da ist INT nur 2 byte groß.
Das liegt nicht an "Ansi-C" (das nennt man heutzutage C89), sondern
daran, daß da entweder 8- oder 16-Bit-CPUs drinstecken.
Harald K. schrieb:>> Ich dachte sizeof(INT) ist plattformabhängig und nicht generell 4.>> Ist es auch nicht.
Wenn wir schon beim klugscheissen sind...
INT ist immer 4 Bytes. Das ist ein typedef in Windows.
Harald K. schrieb:> Das liegt nicht an "Ansi-C" (das nennt man heutzutage C89), sondern> daran, daß da entweder 8- oder 16-Bit-CPUs drinstecken.
Das liegt nur und ausschliesslich am ABI der toolchain. Natürlich wird
da in der Regel Rücksicht auf die Architektur genommen, aber ein Muss
ist das nicht.
Oliver
Udo K. schrieb:> Wenn wir schon beim klugscheissen sind...>> INT ist immer 4 Bytes. Das ist ein typedef in Windows.
Wenn wir schon beim Klugscheissen sind, hast Du dich grad selbst
widerlegt.
sizeof(int) ist Plattformabhängig. Und bei Windows halt grad mal 4.
int32_t ist plattformunabhängig, nicht zufälligerweise immer und überall
4 Byte und das soll man auch verwenden
Udo K. schrieb:> Lern mal lesen.
Von dir?
BTW:
Ich war es nicht, der mit INT dahergekommen ist. Die Frage des TO war
plattformunabhängig gestellt.
BTW 2:
Aber es gibt auf µC genug Kasperln, die dem Beitrag
Beitrag "Re: Anfängerproblem mit C" Minuspunkte geben.
Einer der Pluspunkte war von mir.
Die ganze Streiterei um C und seine Regeln und Definitionen erinnert
mich einfach immer wieder an dieses Meme. Egal wie perfekt jemand C
kann, irgendwann übersieht er was und schießt sich dann voll selbst ins
Knie. Ohne Ausnahme.
Grüße von einem Rust-Coder, der sich lange genug mit der C-Grütze
rumgeschlagen hat und jetzt die Show genießt.
Speichernavigation sollte man erst weiter hinten anfangen. Das ist
besser, denn da kommen viele Anfänger durcheinander, wenn die nicht die
Grundlagen erarbeitet hatten.
Ich hatte damals auch Probleme (weil: da kommt doch vieles auf einmal
auf einen zu) und so brauchte ich so um die 2-3 Wochen, um da lockerer
draufzuschauen.
Vielleicht ist es besser, erstmal mit Stackoverflow (nicht die
Internetseite) und gdb in die Speichergeschichte einzusteigen. Kann
jedenfalls auch hilfreich sein.
Hinsichtlich der Sonderzeichen ist das Erlenkötterbuch gut - da muss man
aber bei der Stange bleiben, damit man die Zusammenhänge behalten kann.
Niklas G. schrieb:>> i = *j; // i ist irgendwas ok>> Ist nicht ok, ist "undefined behavior" (UB) und kann irgendwas bewirken,> z.B. Programmabsturz. Oder der Compiler entfernt einfach die> main()-Funktion komplett, weil er davon ausgehen darf dass UB nie> auftritt und somit die main() Funktion sowieso nie aufgerufen wird, weil> sie immer zu UB führt. Das gilt auch für Lesezugriffe.
das glaube ich erst Mal nicht (ohne es zu wissen):
wenn der Compiler main übersetzt, weiß er doch nicht dass in fn1 ein
undefined behavior auftritt (fn1 könnte ja auch in einem anderen File
sein)
Walter S. schrieb:> Compiler main übersetzt, weiß er doch nicht dass in fn1 ein undefined> behavior auftritt (fn1 könnte ja auch in einem anderen File sein)
Ich hab ja nicht gesagt dass der Compiler das UB erkennen muss. Aber
wenn er es erkennt, darf er das Programm beliebig verunstalten ohne den
C-Standard zu verletzen. Der Standard verlangt nicht vom Compiler,
fehlerhaften Code irgendwie sinnvoll zu übersetzen.
Wenn fn1 in der selben Datei steht wie hier im Beispiel, sieht der
Compiler was darin passiert. Wenn's eine andere Datei ist sieht er es
auch, wenn LTO aktiviert ist.
Nick schrieb:> Von dir?>> BTW:> Ich war es nicht, der mit INT dahergekommen ist. Die Frage des TO war> plattformunabhängig gestellt.
Ja, offensichtlich von mir :-)
INT gibt es im C-Standard nicht.
C unterscheidet zwischen Groß- und Kleinschreibung.
INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer
4-Bytes hat.
Udo K. schrieb:> INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer> 4-Bytes hat.
Quatsch. Du kennst nur nicht genügend Prozessorarchitekturen:
Walter S. schrieb:> das glaube ich erst Mal nicht (ohne es zu wissen):> wenn der Compiler main übersetzt, weiß er doch nicht dass in fn1 ein> undefined behavior auftritt (fn1 könnte ja auch in einem anderen File> sein)
fn1() übergibt einen Zeiger auf einen int Wert. NUR EINEN!
Wenn nun dieser Zeiger inkrementiert wird:
1
j++;// adresse +sizeof(POINTER)
dann zeigt j hinter den angedachten int Wert.
Also ist:
Udo K. schrieb:> Ja, offensichtlich von mir :-)
Ich weiß. :-)
Udo K. schrieb:> INT ist ein in Millionen von Zeilen verwendetes Typedef, das immer> 4-Bytes hat.
Wo ist das immer 4 Btes groß?
Bei dir? In wie vielen Milliarden Zeilen C-Code NICHT?
Mir ist schon klar, dass das K&R-C unzulänglich ist/war und dass von
dort die Ursprünge des Gewurstles, das sich über Dekaden hinzieht,
herkommt.
"Inzwischen" kann man aber die Typen verwenden, die klar in der Größe
definiert sind. Und das sollte man auch.
Bitte dazu mal <stdint.h> lesen, bzw. Kommentare/Erklärungen dazu.
Anekdote:
Ich hatte mal mit dem Propeller von Parallax rumgespielt. In
interessanter 32 Bit Prozessor mit einer verkorksten Sprache "Spin".
Da war ein Integer Typ "word". Irgendwann wundere ich mich, warum der
nur 16 Bit groß ist und frag im Forum nach. Bis dann der Entwickler des
Propeller (Gracey ?) geantwortet hat, dass "word" immer 16 Bit lang ist.
Auf die Frage woher denn die Definition kommt:
Er hat den Compiler für Spin in Assember (total gaga, aber Respekt für
die Arbeit) 8086 (jedenfalls ein 16-Bitter) geschrieben und da ist das
halt ein word.
Den Compiler mussten sie komplett neu schreiben, ASM ist nicht
sonderlich portabel. Spin wurde dann um C ergänzt, der Propeller
verschwindet so langsam in der Versenkung. Bis auf eine extrem
engagierte Fan-Gemeinde.
long, double, long long, unsigned char, das ist völlig ballaballa.
Leute, schreibt euren code plattformunabhängig und leserlich.
Ah, und zum Rust-Kommentar:
Ja, da geb ich dir Recht. Der Designer hatte wohl genug unter C
gelitten. Ich warte noch darauf, dass Rust endlich mal auf µC
implementiert wird. Der eine STM32 (oder was) ist reichlich wenig um
sich da drauf einzulassen. Ich wäre aber sofort dabei! Hab aber Rust
seit zwei Jahren nicht mehr angefasst.
Norbert schrieb:> fn1() übergibt einen Zeiger auf einen int Wert. NUR EINEN!> Wenn nun dieser Zeiger inkrementiert wird:
Das weisst du doch nicht. Der Zeiger wird meistens ein Feld sein.
Nick schrieb:> dass "word" immer 16 Bit lang ist. Auf die Frage woher denn die> Definition kommt
Tja, bei ARM ist ein Word 32bit, ein Halfword 16bit, und ein Doubleword
64bit.
Aber man kann sich auf Folgendes verlassen:
Die Größe eines int ist: sizeof(int)
Gilt auch für char,short,long,…,char*,short*,long*,…
Und mehr Annahmen macht man einfach nicht!
Johann L. schrieb:> Und wo ist da INT?
Zeile 5: int i, j;
> Übrigens word das printf u.U. nie erreicht (Signed Overflow).
Komisch, bei mir schon.
Die resultierende Ausgabe habe ich oben mitgepostet...
Niklas G. schrieb:> Norbert schrieb:>> sizeof(int)>> Und was genau bedeutet die Zahl die da zurückkommt? 😉
Das ist wie bei einer Schranke, man kann entweder die Höhe oder aber die
Breite feststellen.
Norbert schrieb:> Aber man kann sich auf Folgendes verlassen:> Die Größe eines int ist: sizeof(int)> Gilt auch für char,short,long,…,char*,short*,long*,…> Und mehr Annahmen macht man einfach nicht!
Doch, eine: sizeof(char) ist 1. Immer.
Oliver
Norbert schrieb:> Und mehr Annahmen macht man einfach nicht!
Ich meine, man kann sich bei C darauf verlassen, dass int mindestens
16 Bit groß ist. So war das jedenfalls viele Jahre lang und es wäre
ziemlich dumm, innerhalb der selben Sprache davon abzuweichen.
Nemopuk schrieb:> Ich meine, man kann sich bei C darauf verlassen, dass int mindestens> 16 Bit groß ist.short ist (aus dem Gedächtnis) auch als <= int und long als >=
int definiert. Und short muss < long sein. Das ist allerdings
alles relativ… ;-)
int könnte also 16/32Bit und vielleicht sogar bald 64Bit (bei den
demnächst erscheinenden 128Bit Prozessoren, Speicher kostet ja gerade
nichts) breit sein. ;-)
Norbert schrieb:> for (unsigned long idx = 0; idx < sizeof(array_of_ints)/sizeof(int);> idx++) {
"unsigned long". <tiefes Durchschnaufen>
der Rückgabewert von sizeof ist size_t
Norbert schrieb:> short ist (aus dem Gedächtnis)
Man sollte Anfängern (der TO) solches Methusalem-Wissen nicht
beibringen.
Es existiert nur, um alte Programme noch compilierbar zu halten.
Rust hat damit konsequenterweise komplett aufgeräumt.
Rick schrieb:> Johann L. schrieb:>> Und wo ist da INT?> Zeile 5: int i, j;
Die steht "int" und nicht "INT"!
>> Übrigens word das printf u.U. nie erreicht (Signed Overflow).> Komisch, bei mir schon.> Die resultierende Ausgabe habe ich oben mitgepostet...
Dass ein Programm das macht, was du erwartest, bedeutet nicht, dass es
korrekt ist :-)
Die Logik ist:
> Programm macht nicht was du erwartest => Programm ist inkorrekt
und
> Programm ist korrekt => Programm macht was du erwartest
Was NICHT gelten MUSS:
> Programm ist inkorrekt => Programm macht nicht was du erwartest
sowie
Programm macht was du erwartest => Programm ist korrekt.
> Komisch, bei mir schon.
Weil Undefined Behaviour kein definiertes Verhalten erfordert
- Programm kann das machen was du erwartest (was immer das ist)
- Programm kann nicht-funktional sein.
- Compiler kann eine Diagnostic ausgeben
- Compiler kann terminieren
- Programm kann sich aufhängen / abstürzen.
Letzteres passiert zu Beispiel mit GCC 13. Und mit Sanitizer:
$ gcc x.c -Os -o x.x -fsanitize=undefined && ./x.x
x.c:11:10: runtime error: signed integer overflow: 2147483647 + 1 cannot
be represented in type 'int'
Was geht ist -fwrapv, also modular wrap-around:
$ gcc x.c -Os -o x.x -fwrapv && ./x.x
2147483647 -2147483648
Norbert schrieb:> Wusste gar nicht, dass wir nun bei Rust sind. ;-)
Nein, sind wir nicht. Da Rust schon was mit C gemeinsam hat und
gleichzeitig völlig anders ist ... An der Speicherverwaltung wird man
sich in Rust (aber auch weitaus unbewusster und einfacher in C) zuerst
die Zähne ausbeissen.
Damit hat Rust aufgeräumt, weil es in C saugefährlich ist (siehe oben)
aber gleichzeitig schon auch recht praktisch ist.
Der typgrößenwirrwar von C lässt sich leider nur durch komplettes
ignorieren der alten Herangehensweise beheben. Und ein gutes Beispiel
dafür wie es richtig ist, ist halt Rust. Oder/und exklusiv <stdint.h> zu
verwenden.
Es hilft schon etwas, andere Sprachkonzepte anzuschauen. Da gibt es gute
Lösungen an denen man sich orientieren kann.
Nick schrieb:> Es hilft schon etwas, andere Sprachkonzepte anzuschauen. Da gibt es gute> Lösungen an denen man sich orientieren kann.
Verstehe worauf du hinaus willst, aber gerade für den von dir zitierten
Anfänger kann das aber nur noch verwirrender sein. Wenn man C dann
einigermaßen im Griff hat und wenn sich die Notwendigkeit ergibt, dann
schaut man sich (mit diesem Grundlagenwissen) Anderes an. Python nutzt
zB. nur eine int Klasse, die aber praktisch beliebig groß werden darf.
Norbert schrieb:> Python nutzt> zB. nur eine int Klasse, die aber praktisch beliebig groß werden darf.
Das ist halt eine andere Lösung.
C ist ein "Hochsprachenassembler", wo man oft genug Platz sparen muss
oder auf die Hardware eingehen muss (Ports mit 8 I/O etc.).
Wenn man C so lernen will, dass int immer richtig ist, dann entdeckt man
irgendwann, dass man long braucht. Also bin ich der Meinung, dass man es
von Anfang an richtig lernen soll. Dass es streng definierte Typen gibt
und man damit ganz gut zurecht kommt.
C ist auf µC sehr gut aufgehoben. Für dem Desktop gibt es besser
geeignete Sprachen.
Wenn einem das nicht gefällt, dann soll er halt Python hernehmen. Oder
Java, oder Rust, oder C++, oder Swing, oder C#. Das hat alles seine Vor-
und Nachteile. Es ist aber nicht hilfreich, die
Sprachkonzepte/Paradigmen zu ignorieren oder sie nicht zu akzeptieren.
Man will ja mit einer Sprache programmieren, nicht gegen.
Man kann ja mal versuchen C in OCamel zu übersetzen. Oder gerne auch die
andere Richtung.
Norbert schrieb:> Python nutzt zB. nur eine int Klasse, die aber praktisch> beliebig groß werden darf.
In C/C++ heißt es eben nicht "int" sondern "_BitInt".
Frank D. schrieb:> Das sind aber Anfängerprobleme
Willst du damit ausdrücken, der ganze C-Code, in dem dauernd
Sicherheitslücken aufpoppen, sei ausschließlich von Anfängern
geschrieben?
Nein, das ist natürlich nicht so.
Ob S. schrieb:> Nein, das ist natürlich nicht so.
Es gibt auch Leute, die sehr lange Dinge machen, die sie nicht richtig
können.
Klar, denen kann man dann mit betreuten Programmiersprachen für
"inklusives Programmieren" entgegenkommen, aber vielleicht wäre
Rosenzüchten doch besser?
Johann L. schrieb:> In C/C++ heißt es eben nicht "int" sondern "_BitInt".
Na ja, aber man muss sich vorher festlegen und nach dem Kompilieren
bleibt es statisch (wenn ich das richtig sehe).
Das ist etwas völlig anderes als sich selbst dynamisch nach Bedarf
anpassende Integer (wachsend und schrumpfend).
Des weiteren ist es auch noch arg limitiert.
Um mal mein Beispiel in C zu zeigen, für 7^7^7 braucht es 2311998 Bits
Norbert schrieb:> Das ist etwas völlig anderes als sich selbst dynamisch nach Bedarf> anpassende Integer (wachsend und schrumpfend).
Ich nehme einfach mal an, dass es sowas (inzwischen) auch in C++ gibt.
In Rust (sorry) gibt es das auch:
1
usenum_bigint::BigUint;
Das ist die dynamische Version. Gibt auch statische Versionen.
Man kann sich solche Sachen doch selbst bauen. Auch in C. Ich brauchte
mal dynamische Arrays. Dann schreib ich mir die halt, das dauert keinen
Tag und man kann die ab dann immer wieder verwenden.
"Das gibts nicht" ist eine etwas einfältige Einstellung.
Nick schrieb:> Man kann sich solche Sachen doch selbst bauen.
Bauen kann man sich alles Mögliche. Da braucht man noch nicht einmal
eine Programmiersprache, das geht auch in BASIC.
Hier geht es aber darum was eine Sprache (in diesem Fall C) zur
Verfügung stellt, nicht was man hinterher nach- und dazubasteln kann.
Übrigens geht es auch nicht um C++.
Harald K. schrieb:> Es gibt auch Leute, die sehr lange Dinge machen, die sie nicht richtig> können.
Oder halt auch Leute, die einfach nur Menschen sind und dementsprechend
auch Fehler machen. Möchtegern-Göttern wie dir passiert so etwas
natürlich niemals.
Das haben allerdings wohl auch all die anderen erfahrenen
C-Programmierer gedacht, die die Fehler produziert haben: Ich kann das,
ich mache keine Fehler.
> Klar, denen kann man dann mit betreuten Programmiersprachen für> "inklusives Programmieren" entgegenkommen
Natürlich ist das der sinnvollste Ansatz! Ein Hochsprache, in der
Menschen programmieren sollen, hat es den Menschen so einfach wie
möglich zu machen, keine Fehler zu produzieren, sonst taugt sie nix.
Wenn es z.B. sowas wie UB gibt, dann hat der Compiler die verdammte
Pflicht, zu warnen und darf nicht einfach stillschweigend Code
entfernen, weil ihm der überflüssig vorkommt. Er darf und sollte(!)
einfach sagen, dass er ihm überflüssig vorkommt.
Alles andere ist menschenuntauglicher Bullshit.
Ob S. schrieb:> Möchtegern-Göttern wie dir passiert so etwas> natürlich niemals.
Och, den Möchtegern-Gott sehe ich doch eher bei Dir, lieber "C-Hater".
Hier mal etwas aktuelles passendes Schulfernsehen dazu:
https://www.youtube.com/watch?v=ZcCo_Iywilk
Also entweder ihr koennt C oder ihr bereitet auch auf die
Arbeitslosigkeit vor.
Vanye
Vanye R. schrieb:> Also entweder ihr koennt C oder ihr bereitet auch auf die> Arbeitslosigkeit vor.
Claude kann kein C?
Wir lassen uns jetzt von KI-generierten Videos erklären warum C die
einzige Sprache mit Jobsicherheit ist, was ja eigentlich nur sein könnte
wenn es nicht KI-generierbar wäre?
Nick schrieb:> Man kann sich solche Sachen doch selbst bauen. Auch in C.
Gibt's doch alles, als FOSS:
Ganze und Rationale Zahlen: GMP https://gmplib.org
Reelle Zahlen (Floating): MPFR https://www.mpfr.org
Complexe Zahlen (Floating): MPC https://www.multiprecision.org
GMP has a rich set of functions, and the functions have a regular
interface. The basic interface is for C, but wrappers exist for
other languages, including Ada, C++, C#, Julia, .NET, OCaml, Perl,
PHP, Python, R, Ruby, and Rust.
Johann L. schrieb:> Gibt's doch alles, als FOSS:
Wozu dann das Gejammere. :-)
Nein, kannte ich nicht. Danke für den Hinweis.
Hätte mir aber auch nichts bei den dynamischen Arrays geholfen.
+ "Not invented here"-Syndrom.
Aber falls ich mal riesen Zahlen brauch, hoffe ich mich daran zu
erinnern.
Nick schrieb:> Ich warte noch darauf, dass Rust endlich mal auf µC> implementiert wird.
Clang/LLVM unterstützt Rust und AVR.
Und im GCC ist Rust in der Mache:
Die einzige Frage ist wieviele Leute es gibt, die sich mit Rust
auskennen UND mit AVR auskennen UND mit Compiler-Interna auskennen UND
die nötigen Resourcen (Lust, Zeit, ...) mitbringen, um da was zu
bewegen.
Zumindest bei G++ ist diese Schnittmenge über die letzten 25 Jahren
effektiv leer...
Johann L. schrieb:> Clang/LLVM unterstützt Rust und AVR.
Die AVR-Unterstzung in C/C++ war doch bisher eher theoretisch, aber kaum
praktisch nutzbar. Hat sich das inzwischen geändert?
Oliver
Oliver S. schrieb:> Die AVR-Unterstzung in C/C++ war doch bisher eher theoretisch
Die C Unterstützung für AVR ist theoretisch? Vielleicht hast ja die
letzten 25 Jahre verpennt :-)
Zu C++ schrub ich:
Johann L. schrieb:> Die einzige Frage ist wieviele Leute es gibt, die sich mit Rust> auskennen UND mit AVR auskennen UND mit Compiler-Interna auskennen UND> die nötigen Resourcen (Lust, Zeit, ...) mitbringen, um da was zu> bewegen.>> Zumindest bei G++ ist diese Schnittmenge über die letzten 25 Jahren> effektiv leer...
Zu Clang/LLVM weiß ich nix, da hakelt es Teilweise schon mit C weil es
keine dedizierte Libc gibt. Und Clang ist an vielen Stellen
inkompatibel mit GCC, d.h. Piggypack auf AVR-LibC funktioniert nicht
wirklich gut.
Johann L. schrieb:> Die C Unterstützung für AVR ist theoretisch? Vielleicht hast ja die> letzten 25 Jahre verpennt :-)> …> Zu Clang/LLVM weiß ich nix, da hakelt es Teilweise schon mit C weil es> keine dedizierte Libc gibt.
Ja, was denn jetzt? Kann man clang ernsthaft für den AVR (C/C++/Rust,
was auch immer) nutzen, oder nicht?
Oliver
Der Code ist UB. Was beim Overflow eines signed int passiert, ist
nicht definiert. Einige Compiler machen daraus deshalb eine
Endlosschleife: https://godbolt.org/z/qnc48jYM8