Zitat:
Zitat von Siro
Was hab ich für ein Problem mit "C" ?????
Angefangen hat alles mit Bits und Bytes.
"C" kennt aber gar kein Byte.
Das kann man sich dann selbst definieren, (unsigned char)
Besser ist, ein Standard-Header wie <stdint.h> zu verwenden und Typen wie uint8_t, ein unsigned int, der 8 Bit breit ist. Ja, du kannst fluchen wie'n pubertierender Rohrspatz, aber wenn du durch musst, musst du eben durch. Rumzetern bringt dir nix ausser Magengeschwüre. Oder nen neuen Job suchen. Oder die Putze macht den C-Kram und du die Klo-Kosmethik...
Anfangs kannst du es noch auf das Sche..-C schieben, wenn dir alles um die Ohren fliegt, aber irgendwann bleibt's an dir hängen wenn du es nicht lernen willst.
Zitat:
also eine Ableitung von einem "negativen Ascii-Character" ohne Vorzeichen.
Was für ein Scheiss ist das denn....
nö, unsigned heisst, daß das höchstwertige Bit nicht als Vorzeichen interpretiert wird, im Gegensatz zum signed.
Zitat:
Bei Abfragen ob etwas gleich ist, muss man
nicht etwa "=" schreiben, das wär wohl zu "ungenau",
nein, man muss "==" schreiben, also "besonders gleich"
Vernünftige Compiler können Boolsche Ausdrücke von logischen Ausdrücken selbst unterscheiden. Bei "C" geht das nicht. Und da es schon nicht geht, können wir auch gleich noch entsprechende Sonderzeichen einführen, dann merkt man das nicht sofort.
Dir ist klar, daß C 40 Jahre alt ist? Es würde nicht entworfen, um leicht verständlich zu sein. Es wurde nicht von Bastlern entworfen und war auch nicht für Bastler gedacht. Zu der Zeit war man froh, daß es überhaupt möglich war, Compiler zu schreiben und die Assembler-Untiefen zu verlassen. Heutige Sprachen können viel mehr, aber nen Garbage-Collector oder Hashtables wie in Java, die zur Sprache dazu gehören, waren damals einfach unvorstellbar. C läuft vielfach "on the bare metal", auch heute noch. Der Erfolg der Sprache ist auch darin begründet, daß eben nicht ständig daran rumgesäbelt würde uns es abertausende Dialekte gibt die die Portierbarkeit komplett untergraben.
Zitat:
Aus XOR wird ^
aus AND wird &
Und auch hier heisst es wieder "besonders und" && oder
besonders oder "||" was generell mit Klammern umschrieben wird.
Naja wen wundert es da noch, daß man für "<>" kleiner größer auch gleich
was neues erfunden hat: != also "Achtung Nicht Gleich" ist gemeint.
Zitat:
Achja, habt Ihr schon mal versucht mit Strings zu arbeiten in "C"
Das war anscheinend nie vorgesehen und so hat man eine Bibliothek
namens "strings" rangebastelt.
Wozu soll das in den Sprachkern, wenn's in einer Bibliothek geht? Ist in C++ auch so, es ist in Java so (nicht unbedingt mit Strings aber viele andere Sachen sind in Libs), es ist in Python so und weiß der Teufel wo noch überall.
Zitat:
Nun sollte man aber nicht glauben, daß man damit "vernünftig" arbeiten kann.
Doch. Wenn man weiß was man tut, durchaus. Einfach mal rumtippsen nach dem Motto "ja, wird schon gehen ich tippse einfach mal was zusammen" wie in Clicki-Bunti funktioniert eben nicht und früher oder später hat's dich am Arcsh.
Zitat:
Wo ist denn die Funktion zum Einfügen eines Characters oder Strings in einen
Vorhandenen ???
Nimm eine Bibliothek. Oder schreib dir eine. Du hast eine Turing-vollständige Sprache zur Hand, mit der geht das :o)
Zitat:
Die Fehlerhäufigkeit in meiner Software ist exponentiell zum "verkürzten, kryptischen C Code" angestiegen.
Die Fehlerhäufigkeit steigt exponentiell mit der Unkenntnis der Sprache.
Zitat:
Nullterminierte Strings sind einfach "Grütze" darf ich das so sagen ???
Erstmal "durchhechten" wo denn die 0 zu finden ist. Wenns dann etliche Kilobyte sind absolute Resourcenverschwendung.
Wenn du es effizient haben willst, schiele nicht auf Java (da ist es nämlich eben /nicht/ effizient, sondern suche nach effizienten Lösungen in C. Wenn es günstig ist, die Länge mitzuführen, dann bau dir Funktionen/Datentypen, die das für dich erledigen und verwende sie.
Zitat:
Für eine komplexe Software oder auch nur zur Dokumentation hat man (hoffentlich) ein Flussdiagramm, Ablaufdiagramm Jordan oder was auch immer. Durch die Optimierung eines Compilers, stimmt dieser Ablauf aber unter Umständen garnicht mehr.
Falsch. Wenn der Ablauf nicht stimmt, hat der Compiler einen Fehler. Eine Sprache wie C hat eine bestimmte Semantik, die festlegt, was was bedeutet und wie was umgesetzt wird. In C ist es das Konzept einer abstrakten Maschine, deren Zustand an bestimmten Stellen mit denen der realen Maschine übereinstimmen. Diese Stellen heissen "sequence points". Die reale Maschine wiederum wird durch Code dargestellt , der sich so zu verhalten hat, wie dir abstrakte Maschine.
Zitat:
Wenn ich im Diagramm festlege, daß bei einem bestimmten Ereignis z.B eine Unterfunktion angesprungen wird und es auch so
programmiert habe, kann mir der Compiler einen Strich durch die Rechnung machen. Je nach Einstellung macht er plötzlich keinen Unterprogrammaufruf sondern fügt den Code direkt in das aufrufende Programm ein. Das spart Zeit, ist schlau und auch funktionell. Leider entspricht es nicht meinem Flussdiagramm.
Siehe oben. Man kann auch erzwingen, daß ein Funktionsaufrur getätigt wird, aber wenn du davon ausgehst, daß er auf jenen Fall stattfindet oder auf keinen Fall stattfindet wenn da inline steht, hat deine Anwendung ein Problem. Gleiches gilt für Schleifen, das Anlegen von Variablen, für Speicherzugriffe, oder was auch immer: Das Programm muss sich nur nach dem verhalten, was in der Quelle steht, es aber nicht wirklich tun. Steht da a=1; a=a+2 kann der Compiler ein a=3 daraus machen oder es ganz weglassen wenn a nie verwendet wird.
Zitat:
Wenn ich z.B eine Stackbelastung vorausberechne liege ich dann
falsch, diesmal im positiven Sinne, weil weniger Stack benötigt wird. Es könnte aber auch sein, daß ich mich darauf verlassen habe, daß mittels Assembler Code auf die Stackvariablen zugegriffen wird. Das weis natürlich nicht der Compiler und es würde in die Hose gehen. Hier habe ich aber schon aus diesem Forum erfahren, daß die meisten Compiler eine Schalter haben um diese Optimierung abzuschalten. -noinline oder ähnliches.
Optimierung ganz zu deaktivieren ist eine Option. Das entbindet dich aber nicht davon, die Sprache zu beherrschen. Dann: wo ist da Assembler? Wenn du in Assembler schreibst, musst du spezielle Regeln einhalten und dich nach dem ABI des Compilers richten. Das wird nochmal unbequemer. Du kannst nicht einfach non chalant Assembler und C (oder irgend eine andere Hochsprache) mischen und erwarten das das funktioniert.
Zitat:
Einen wirklich "Eindeutigen" Code, unabhängig von irgend welchen Compiler Einstellugnen, habe ich nur wenn ich in Assembler programmiere.
Nein, je nach Assembler noch nicht mal das. Es gibt Assembler, die zB Branch-Relaxing ausführen oder Hardware-Bugs umschiffen.
Zitat:
Das hab ich auch die letzten 30 Jahre getan. Nun blick ich oftmals durch den erzeugten Code vom C-Compiler nicht mehr durch.
Das ist auch ganz und garnicht einfach, selbst mit einem guten Debugger. Aber mit Asm-Erfahrung hast du da gute Voraussetzungen. Wenn dir was in C nuklar ist, kannst du zB ne kleine Testfunktion machen und siehst, wie der Compiler das umsetzt und kommst so vielleicht besser in die Sprache ran als mit Büchern.
Zitat:
Ist schon "witzig" je nach Compiler Einstellung ist mein Code zur Zeit 14 KByte oder 8 KByte groß. Wie soll man denn das dokumentieren ? zwecks ISO usw. ???? Was steht denn in den "verlorenen" 6 KByte ??? Für Sicherheitsrelevenate Anwendungen z.B. in der Medizintechnik ist das für mich unverantwortlich, mal eben 6 KByte Code wegzulassen. Wenns dann funktioniert okay....
In Assembler konnte ich bisher jedes Bit nachweisen, was es tut, warum, und zu welchem Zeitpunkt.
Die 8kB waren dann schlichtweg nicht notwendig. Der Compiler hat das erkannt und Code wiederverwendet, nicht verwendete Sachen rausgeschmissen, was auch immer.
Der Nachweis muss muss dann eben jetzt auf C-Ebene geschehen oder mit Hardware-Unterstützung (Timer, ...) Inline-Assembler ist eine Option, aber es ist in den meisten Fällen weder notwendig noch dient es der Verständlichkeit, Wartbarkeit oder Portierbarkeit. Falls Für irgendwas Ticks gezählt werden müssen, kommt man an Assenbler nicht vorbei.
Zitat:
In C kann ich ja nichtmal die Laufzeit angeben für eine Funktion, da sie sich je nach Optimierung ändert. In Assembler habe ich die Laufzeiten in Nano Sekunden dokumentieren können.
Auf einer Hardware, die mehrere Pilelines hat, unterschiedlich schnelle Speicher anbindet, über Caches verfügt, Delay-Slots hat, Jump Prediction, oder mit Hardware-Bugs gepflastert, wirst du dir da die Finger blutig rechnen und einem C-Compiler die Füsse küssen.
Was sicherheitskritische Anwendungen angeht: Hier mit Bleistift und Papier einem Compiler hinterher zu rechnen (selbst wenn er nicht optimiert), ist keinem Progrmmierer zuzumuten. Wenn deinem Arbeitgeben das Kleingelt für entsprechende Tools fehlt, soll er dich weiter in Assembler schreiben lassen. Für Sicherheitsfritische Saftware im Bereich AKW oder Avionics sind entsprechende Tools schon für läppische 40000€ zu haben (benötigte Hardware und Analysezeit nicht eingerechnet), für Medizintechnik wird also die Portokasse deines Brötchengebers reichen.
Von Hand nachrechnen ist auch daher inakzeptabel, weil Codeänderungen /nicht/ lokal sind, d.h. eine Änderung im Code kann sich an ganz andere Stelle so auswirken, daß der Compiler zB anderer Register als günstig erachtet (so wie du es als Asm-Progger auch machen könntest, aber um Änderungen lokal zu halten eben nicht tust) und die komplette Rechnung neu angefangen werden muss. Oder es wird komplett ohne Optimierung gearbeitet (was je nach Sicherheitsstufe angezeigt ist) aber dann muss die Hardware deutlich fetter ausgelegt werden, da ein C-Compiler dann wesentlich mehr Overhead erzeugt als ein Assembler-Programmierer (sowohl was Laufzeit als auch was Codedichte uns Stackbedarf angeht).
Bei Java wären solche Zeitabschätzungen gar nicht mehr möglich.