Hallo,
ich erstelle ein array, mit 8 Elementen (in c).
Jetzt frage ich ausversehen das 10. Element ab. Da steht dann natürlich
Müll drinn. Wo greife ich dann genau hin? Direkt auf den Wert in der
nachfolgenden Adresse? Oder ganz woanders? Kann es Möglichkeiten geben,
was zum Absturz oder so führen könnten?
Felix schrieb:> Direkt auf den Wert in der> nachfolgenden Adresse?
Ja.
Felix schrieb:> Kann es Möglichkeiten geben,> was zum Absturz oder so führen könnten?
Beim Lesen kann eher nichts passieren (kommt auf dein Programm an).
Schreiben kann da eher zu Problemen führen.
Felix schrieb:> Wo greife ich dann genau hin?
Das ist undefiniert. Bei einer einfachen linearen Speicheradressierung
(wie sie Mikrocontroller meist haben) würdest du damit auf die
Speicherzellen hinter dem Array zugreifen.
Bei Systemen mit Memory Mapping Unit ist das Ergebnis unbestimmt. Wenn
du Glück hast, liegt dahinter Speicher, der deinem Programm gehört. Wenn
nicht, führt der Versuch, auf fremden Speicher zuzugreifen womöglich zu
einem Programmabbruch.
> Kann es Möglichkeiten geben, was zum Absturz oder so führen könnten?
Ja. Wie gesagt kann die Memory Mapping Unit bzw. das Betriebssystem den
Zugriff verbieten. Bei vielen Mikrocontrollern sind auch I/O Register in
den Speicher gemappt, bei denen sogar Lesezugriffe schon Seiteneffekte
auslösen. Bei einem seriellen Port könnte ein Lesezugriff z.B. bewirken,
dass das gelesene Byte aus einem Empfangs-Strom verloren geht.
Wenn der Compiler mitbekommt, daß Du da out of bounds zugreifst, kann er
auch die ganze Funktion wegoptimieren, oder gleich das ganze Programm.
Oder sonstwas für Code erzeugen.
Felix schrieb:> ich erstelle ein array, mit 8 Elementen (in c).> Jetzt frage ich ausversehen das 10. Element ab.> Wo greife ich dann genau hin? Direkt auf den Wert in der> nachfolgenden Adresse?
Implementation defined. Oder auf gut Deutsch: hängt vom Compiler ab. Der
Compiler ordnet deine Variablen im Speicher an. Weitgehend nach seinem
Gusto. Typisch liegen alle globalen und statischen Variablen beieinander
im Speicher (im Datensegment). Du greifst dann also auf eine andere
Variable bzw. auch nur auf einen Teil einer anderen Variable zu.
> Kann es Möglichkeiten geben,> was zum Absturz oder so führen könnten?
Auf µC eher nicht. Aber PC Betriebssysteme ergreifen Maßnahmen, um
Programme voneinander abzuschotten. Wenn du beim Zugriff über das
Arrayende hinaus den Speicherbereich deines Programms verläßt, läßt das
Betriebssystem es abstürzen. Windows-User kennen das als
"Schutzverletzuung"
Axel S. schrieb:> Implementation defined.
'array out of bounds' ist undefined behaviour, keineswegs implementation
defined.
Passieren kann also so ungefähr alles; in den meisten Fällen dürfte
schlicht ein falscher Wert (möglicherweise der einer anderen Variable)
zurückgeliefert werden oder (Speicherschutz an einer Page-Grenze) ein
Crash resultieren.
Axel S. schrieb:> Auf µC eher nicht
Doch, so ziemlich alle ARM Controller haben unbenutzte Speicher
Bereiche, wenn man da drauf zugreift (egal ob lesen oder schreiben) gibt
es eine Fault Exception ("Absturz").
STK500-Besitzer schrieb:> Felix schrieb:>> Kann es Möglichkeiten geben,>> was zum Absturz oder so führen könnten?>> Beim Lesen kann eher nichts passieren (kommt auf dein Programm an).> Schreiben kann da eher zu Problemen führen.
Doch, das Betriebssystem kann sagen "He, das ist gar nicht dein
Speicher!". Wird auch oft passieren.
Felix schrieb:> Jetzt frage ich ausversehen das 10. Element ab.
Manchmal ist das sogar gewollt, z.B. die "Nutzdaten" nach einen
bestimmten Header für unterschiedlich lange Telegramme.
Wenn es nicht gewollt ist, dann sorge dafür, dass Compiler-Warnungen
oder Lint dir das anzeigen. Liegt dahinter eine andere Variable, die
überschrieben wird, dann kann diese beliebige Fehler nach sich ziehen.
Oder liegt dort ein Register, dann kann auch rein lesend schon Müll
passieren, egal, was Dein Compiler daraus macht.
Stefanus F. schrieb:> Felix schrieb:>> Wo greife ich dann genau hin?>> Das ist undefiniert. Bei einer einfachen linearen Speicheradressierung> (wie sie Mikrocontroller meist haben) würdest du damit auf die> Speicherzellen hinter dem Array zugreifen.>> Bei Systemen mit Memory Mapping Unit ist das Ergebnis unbestimmt. Wenn> du Glück hast, liegt dahinter Speicher, der deinem Programm gehört. Wenn> nicht, führt der Versuch, auf fremden Speicher zuzugreifen womöglich zu> einem Programmabbruch.
Ich sehe es genau umgekehrt: Wenn du Glück hast, wird das Programm
abgebrochen, und du merkst dadurch gleich, dass es einen Fehler hat.
Wenn du Pech hast, scheint es beim Test problemlos zu laufen, und
nachher im Einsatz passieren dann merkwürdige scheinbar unerklärliche
Dinge.
Axel S. schrieb:> Der Compiler ordnet deine Variablen im Speicher an. Weitgehend nach> seinem Gusto.
Das macht bei Variablen mit statischer Lebensdauer in der Regel der
Linker.
>> Kann es Möglichkeiten geben,>> was zum Absturz oder so führen könnten?>> Auf µC eher nicht. Aber PC Betriebssysteme ergreifen Maßnahmen, um> Programme voneinander abzuschotten. Wenn du beim Zugriff über das> Arrayende hinaus den Speicherbereich deines Programms verläßt, läßt das> Betriebssystem es abstürzen. Windows-User kennen das als> "Schutzverletzuung"
Bei PC-Betriebssystemen ist der Speicher der Programme eh virtualisiert
durch Paging. Speicher, der anderen Programmen gehört, ist also aus
Sicht deines Programmes gar nicht existent.
Es gibt Sicherheitslücken, bei denen bewusst über Arraygrenzen
geschrieben wird. So kann man zum Beispiel ausführbaren Code in Bereiche
schreiben, die später ausgeführt werden.
Mir fällt der Name gerade nicht ein, aber das war früher eine relativ
häufige Lücke.
Dussel schrieb:> Es gibt Sicherheitslücken, bei denen bewusst über Arraygrenzen> geschrieben wird.
Das nennt sich buffer overflow oder deutsch Pufferüberlauf.
> So kann man zum Beispiel ausführbaren Code in Bereiche> schreiben, die später ausgeführt werden.
Der AVR ist da glücklicherweise außen vor, weil Harvard-Architektur.
Mainstream-Architekturen nutzen die MMU dazu, ausführbaren Speicher und
vom Programm beschreibbaren Speicher zu trennen.
Beim Stack bleibt da leider eine Lücke. Ein Pufferüberlauf bei lokalen
Variablen erlaubt möglicherweise die Manipulation der Rücksprungadresse.
> das war früher eine relativ häufige Lücke.
Leider nicht nur früher. C mit seiner bescheidenen Implementierung von
Strings lädt leider dazu ein. Wenn man in C mit Strings hantiert, sollte
man sich angewöhnen, von allen Funktionen die Variante mit dem extra "n"
im Namen und der Pufferlänge als extra Parameter zu verwenden. Also
strncpy() statt strcpy() oder auch snprintf() statt sprintf(). usw. usf.
Oder vielleicht besser gleich C++ und richtige Strings verwenden.
Axel S. schrieb:> Also strncpy() statt strcpy() oder auch snprintf() statt sprintf(). usw.> usf.
Gerade strncpy() wird auch als gefährlich eingestuft, da es an den
Zielstring kein \0 anhängt, wenn der Quellstring zu lang ist (dafür aber
unnötig viele davon, wenn er kürzer ist). Wer da nicht immer drauf
achtet, hat ruck-zuck auch einen Buffer-Overflow, nicht im strncpy()
selber, aber beim nächsten Iterieren durch den String dann.
Aus dem Grund gibt es auf einigen Systemen eine Funktion strlcpy(), die
immer einen korrekten C-String erzeugt, sofern der Input auch einer
ist.
A. S. schrieb:> Manchmal ist das sogar gewollt, z.B. die "Nutzdaten" nach einen> bestimmten Header für unterschiedlich lange Telegramme.
Das macht man so nicht, schon weil es in jedem Falle undefined behaviour
ist und der Compiler es rauswerfen kann. Das manifestiert sich dann
gerne als unerwarteter Bug nach einem Compiler-Update - insbesondere GCC
ist da sehr rücksichtlos, was Abwärtskompatibilität zu kaputtem Code
angeht.
Deswegen liest man nicht einfach über den Header hinaus, sondern nimmt
die Struktur, in der das Telegramm ja ohnehin stecken wird, und die
einen Datenteil haben muß.
Notfalls wirft man die ganze Struktur in ein Overlay-Char-Array und
fummelt das dann manuell mit Char-Pointern raus, die dürfen schließlich
aliasen.
Nop schrieb:> Das macht man so nicht, schon weil es in jedem Falle> undefined behaviour ist und der Compiler es rauswerfen kann.
Jaein, ich glaube A. S. meint sowas:
1
structtelegramm{
2
chartype;
3
intlen;
4
chardata[]
5
};
Wo man dann mit "data" durch den Datenteil des Telegramms iterieren
kann, wobei die Struktur nur den Header des Telegramms überlagert.
Das ist eine übliche Vorgehensweise. So üblich, dass der GCC genau dafür
eine Erweiterung hat...
S. R. schrieb:> Wo man dann mit "data" durch den Datenteil des Telegramms iterieren> kann, wobei die Struktur nur den Header des Telegramms überlagert.
Achso, ich hatte das eher so verstanden, daß der Header selber ein Array
ist und man den einfach out of bounds liest, weil dahinter ja die Daten
kommen.
Nop schrieb:> out of bounds
In C gibt es die Äquivalenz von Array und Zeiger Zugriffen, welche
zwangsläufig keinerlei Schutz liefert.
Beispiel:
> int array[] = {1,2,5};
und später dann:
> print( 2[array] ); // sagt: 5
oder
> print( array[2] ); // sagt: 5
oder
> print( *(array+2)); // sagt: 5
Diese drei Varianten sind vollkommen gleichwertig
print( 42[array] );
Äquivalent zu
print( *(array+42) );
Welches dann wohl in die Wiese zeigt....
S. R. schrieb:> Das ist eine übliche Vorgehensweise. So üblich, dass der GCC genau dafür> eine Erweiterung hat...
Das ist keine Erweiterung, sondern Standard-C.
Arduino Fanboy D. schrieb:> In C gibt es die Äquivalenz von Array und Zeiger Zugriffen, welche> zwangsläufig keinerlei Schutz liefert.
Das ist eine reine Notationsfrage. Trotzdem sind Arrays und Pointer in C
keineswegs identisch.
Wenn die Speicherreservierung in einer anderen translation unit erfolgt
als der Zugriff, weil das als Pointer an eine Funktion aus einer anderen
Datei übergeben wird, dann dürfte der Compiler den Schmu nicht bemerken.
Ist es hingegen in derselben Datei, dann kann der Compiler durchaus
zuschlagen.
Nop schrieb:> Ist es hingegen in derselben Datei, dann kann der Compiler durchaus> zuschlagen.
Ja?
Welcher?
Der AVR-gcc tut es nicht.
Der lässt es ohne Murren durch.
Egal, ob C oder C++.
Egal, ob in der gleichen Übersetzungseinheit, oder auch nicht.
Weiterhin:
Arduino Fanboy D. schrieb:> keinerlei Schutz
Teste es bitte.
Arduino Fanboy D. schrieb:> Nop schrieb:>> Ist es hingegen in derselben Datei, dann kann der Compiler durchaus>> zuschlagen.> Ja?> Welcher?>> Der AVR-gcc tut es nicht.
Doch, aber natürlich nur dann, wenn bereits zur Compilezeit erkennbar
ist, dass ein Index zu groß wird, wie bspw. hier (avr-gcc-9.1.0 -Os):
Ist die obere Schleifengrenze hingegen das Ergebnis einer komplexeren
Berechnung oder gar einer I/O-Operation, wird keine Warnung ausgegeben.
Das würden auch Compiler für andere Programmiersprachen nicht tun. Da
bliebe dann nur die Laufzeitprüfung, die in C aber kaum praktikabel ist.
Yalu X. schrieb:> Doch, aber natürlich nur dann, wenn bereits zur Compilezeit erkennbar> ist, dass ein Index zu groß wird, wie bspw. hier (avr-gcc-9.1.0 -Os):
Da zaubert er eine Schleife rein.....
Ein Argumentverdreher, er ist...
1
intarray[4];
2
3
intmain(void){
4
array[42]=5;
5
42[array]=5;
6
*(array+42)=5;
7
}
Obwohl deutlich erkennbar, dass der Index zu groß ist, geht es ohne
Murren durch, auch mit avr-gcc-9.1.0 -Os
Arduino Fanboy D. schrieb:> Nop schrieb:>> Ist es hingegen in derselben Datei, dann kann der Compiler durchaus>> zuschlagen.> Ja?> Welcher?
Jeder. In jeder Version nach dem nächsten Update. Ich habe schon genug
kaputten Code gesehen, der nach dem nächsten Compiler-Update nicht mehr
lief. Das verhindert man, indem man sowas gar nicht erst schreibt,
sondern sich mal damit befaßt, was der C-Standard dazu meint.
> Weiterhin:> Arduino Fanboy D. schrieb:>> keinerlei Schutz>> Teste es bitte.
Bauche ich nicht, denn experimentelles undefined behaviour ist Blödsinn
- siehe oben.
Arduino Fanboy D. schrieb:> int array[4];>> int main(void) {> array[42] = 5;> 42[array] = 5;> *(array+42) = 5;> }
GCC 7.3.0 (MingW) warnt übrigens mit -Wall sehr wohl "subscript out of
bounds", das nur der Vollständigkeit halber. Daß er ohne -Wall nicht
warnt, bedeutet nicht, daß er es nicht für unerwartete Optimierungen
nutzen kann.
Arduino Fanboy D. schrieb:> int array[4];>> int main(void) {> array[42] = 5;> }>> Obwohl deutlich erkennbar, dass der Index zu groß ist, geht es ohne> Murren durch
Ok, hier braucht man noch ein -Wall oder -Warray-bounds.
1
test.c:3:9: warning: array subscript 42 is above array bounds of 'int[4]' [-Warray-bounds]
2
3 | array[42] = 5;
3
| ~~~~~^~~~
4
test.c:1:5: note: while referencing 'array'
5
1 | int array[4];
6
| ^~~~~
Wobei ich mittlerweile (nach seinem vorletzten Beitrag) glaube, dass Nop
mit
Nop schrieb:> zuschlagen
etwas anderes gemeint hat.
Nop schrieb:> Jeder.
Gelogen.
Deine Behauptung war, dass der Compiler das meldet.
Und diese ist widerlegt.
Da kannst du an den Haaren herbei ziehen was du willst...
Yalu X. schrieb:> Ok, hier braucht man noch ein -Wall oder -Warray-bounds.
Ja, dann wirds was....
Arduino Fanboy D. schrieb:> Gelogen.>> Deine Behauptung war, dass der Compiler das meldet.
Lerne lesen. Meien ursprüngliche Aussage war, ich zitiere mich:
"Wenn der Compiler mitbekommt, daß Du da out of bounds zugreifst, kann
er
auch die ganze Funktion wegoptimieren, oder gleich das ganze Programm.
Oder sonstwas für Code erzeugen."
Ich habe nicht geschrieben, daß er dazu warnen muß. Wenn Du ernsthaft
glaubst, daß der Compiler nur solches undefined behaviour ausnutzen
würde, vor welchem er auch warnt, dann bist Du massiv auf dem Holzweg.
Nop schrieb:> "Wenn der Compiler mitbekommt, daß Du da out of bounds zugreifst, kann> er auch die ganze Funktion wegoptimieren, o
Ich bezweifle das. Habe jetzt am Handy nicht den Standard, aber ich habe
den so verstanden: greift man außerhalb des (reservierten) Speichers zu,
undefined behaviour. Hat man Speicher reserviert (wie auch immer), dann
wie erwartet. Egal ob das [] Konstrukt in einer Union steckt, per ptr
auf einen mallocbereich zeigt oder zum memdump dient.
Nop schrieb:> Lerne lesen.
Lerne selber lesen.
Das array[42] = 5; zieht der Compiler durch!
Das optimiert er nicht weg, nur weil/wenn er eine Warnung wirft.
Nop schrieb:> Ich habe schon genug> kaputten Code gesehen, der nach dem nächsten Compiler-Update nicht mehr> lief. Das verhindert man, indem man sowas gar nicht erst schreibt,> sondern sich mal damit befaßt, was der C-Standard dazu meint.
ach was meint denn der C-Standard zu char? singend oder unsigned?
Was ist mit Char über 127?
Ich erlebe da immer wundersames. Möchte ich einfach nur ein Array of
Bytes mit 8 Bit haben, was den vollen Char Umfang ermöglicht (16 Bit mal
ausgenommen) ärgern mich immer so Fehler oder Warnungen von ist defined
als unsigned ist aber signed oder umgedreht. Warum kann ein Byte nicht
einfach uint8_t sein, was ist verwerflich uint8_t auch auf str
Funktionen anzuwenden? (kann denn ein char negativ werden?)
Und jeder Funktion eine Typprüfung oder cast vorzusetzen ist auch nicht
gerade anwenderfreundlich.
Letztens wieder mit Nokia Zeichensatz bis 255, isprint ignoriert alles
über 127
Joachim B. schrieb:> ach was meint denn der C-Standard zu char? singend oder unsigned?> Was ist mit Char über 127?
Ist im Zusammenhang mit aliasing irrelevant, wenn man nur die binären
Daten rausgreifen will.
Arduino Fanboy D. schrieb:> Das optimiert er nicht weg, nur weil/wenn er eine Warnung wirft.
Ich seh schon, Du verstehst von der Materie exakt soviel, wie man es von
einem "Arduino Fanboy" auch erwarten würde. Leute wie Du sind es, die
die Bugtracker der Compiler nach Versionsupdates mit angeblichen
Compilerbugs fluten, weil ihr kaputter Code auf einmal zerbrochen ist.
EOD.
Nop schrieb:> Leute wie Du sind es, die> die Bugtracker der Compiler nach Versionsupdates mit angeblichen> Compilerbugs fluten, weil ihr kaputter Code auf einmal zerbrochen ist.
wer schreibt denn "perfekten" Code?
Ich habe niemanden gefunden, angeblich wird das in einer Uni gelehrt,
aber die das lernen sind i.d.R. keine code monkeys.
Joachim B. schrieb:> Und jeder Funktion eine Typprüfung oder cast vorzusetzen ist auch nicht> gerade anwenderfreundlich.
und überfordert jeden µC oder Programmierer.
Wie kann es sonst sein das Fedora Version23 beim Dateimanger PCMANFM
abschmiert?
Dateifunktionen sollten doch mittlerweile schon funktionieren.
Joachim B. schrieb:> wer schreibt denn "perfekten" Code?
Es ist eine Sache, ob man irrtümlich verkehrten Code schreibt, aber an
sich bestrebt ist, das zu vermeiden - aber eine andere, oder ob man sich
hinstellt und behauptet, kaputter Code sei doch OK, weil er jetzt gerade
mal nicht zerbreche.
A. S. schrieb:> aber ich habe> den so verstanden: greift man außerhalb des (reservierten) Speichers zu,> undefined behaviour.
Ja, aber es ist nicht das Zugriffsverfahren, welches undefiniert ist,
sondern das was passiert, wenn dort zugegriffen wird.
Dem Nop seine Behauptung, dass der Compiler solche Zugriffe unterbindet,
ist schlicht falsch.
Sondern, der Compiler zieht das durch, trotz evtl geworfener Warnung.
Da kann der Nop mich angreifen und beleidigen, wie er will.
Da beißt keine Maus einen Faden von ab.
Nop schrieb:> oder ob man sich> hinstellt und behauptet, kaputter Code sei doch OK
würde mir nie einfallen, dazu ärgere ich mich zu oft über falschen Code.
Aber wie sagte ein Chef mal, manchmal muss man einem Entwickler das Teil
aus der Hand reissen. Gilt offensichtlich auch für Programmierer, zu
vieles ist nicht bedacht worden, manchmal auch einfach vergessen und an
andere Fehlermöglichkeiten denkt man auch mal nicht.
Rolf M. schrieb:>> Das ist eine übliche Vorgehensweise. So üblich,>> dass der GCC genau dafür eine Erweiterung hat...>> Das ist keine Erweiterung, sondern Standard-C.
Stimmt, flexible Arrays sind seit C99 vorhanden.
Vorher hat man ein Array der Länge null angegeben,
was eine GCC-Erweiterung ist.
Arduino Fanboy D. schrieb:> Dem Nop seine Behauptung, dass der Compiler solche Zugriffe unterbindet,> ist schlicht falsch.
Ihr redet aneinander vorbei. Ich hatte den Nop erst auch missverstanden,
was u.a. damit zusammenhing, dass ich nur einen Teil seiner Beiträge
gelesen habe. Spätestens nach seinen zusätzlichen Erläuterungen sollte
aber klar sein, was er gemeint hat, so dass man darauf nicht noch ewig
herumreiten muss.
Joachim B. schrieb:> Warum kann ein Byte nicht einfach uint8_t sein, was ist verwerflich> uint8_t auch auf str Funktionen anzuwenden? (kann denn ein char negativ> werden?)
char dient lediglich als Speicherplatz für ein Zeichen. Da man mit Text
nicht rechnet, ist die signedness egal. Es ist in der Regel nicht
zweckmäßig, es überall auf unsigned zu zwingen, nur weil man der Meinung
ist, dass da kein Vorzeichen sein darf, und sich damit ggf.
einzuhandeln, dass man bei jeder Stringfunktion eine Warnung bekommt,
weil die Signedness nicht passt.
Arduino Fanboy D. schrieb:> Dem Nop seine Behauptung, dass der Compiler solche Zugriffe unterbindet,> ist schlicht falsch.
Wo hat er das denn behauptet?
> Sondern, der Compiler zieht das durch, trotz evtl geworfener Warnung.
Der Compiler darf machen, was er will. Undefiniertes Verhalten ist nicht
auf die Laufzeit des Programms beschränkt. Es heißt, dass alles
passieren kann - auch zur Compilezeit.
Arduino Fanboy D. schrieb:> Dem Nop seine Behauptung, dass der Compiler solche Zugriffe unterbindet,> ist schlicht falsch.
Was daher kommt, daß ich das so nicht behauptet habe und Du nichtmal im
Ansatz begriffen hast, was die Konsequenzen von undefined behaviour
sind. Der Compiler KANN das wegoptimieren. Nicht nur den Zugriff, gleich
die ganze Funktion. Oder auch das ganze Programm. Oder ganz beliebigen
Code erzeugen, z.B. eine Endlosschleife.
Ist es hingegen in einer anderen translation unit in einem
Funktionsaufruf, dann wird der Compiler das nicht wegoptimieren, weil er
in der Funktion nicht weiß, daß der Speicher hinter dem Pointer, zu dem
das Array verflacht ist, nicht ausreicht, und somit das undefined
behaviour nicht sieht.
Dann kann das Programm lediglich ganz normal zur Laufzeit abstürzen
und/oder verkehrte Ergebnisse bringen.
A. S. schrieb:> Nop schrieb:>> "Wenn der Compiler mitbekommt, daß Du da out of bounds zugreifst, kann>> er auch die ganze Funktion wegoptimieren, o>> Ich bezweifle das.
Das Verhalten bei einem out-of-bound Zugriff ist in C nicht definiert.
Es kann alles passieren: Vielleicht soagr etwas mehr oder weniger
erwartetes; oder aber die Funktion wird wegoptimiert; oder, ess regnet
rosarote Elefanten. :-)
Ich komme eher aus der Asm Ecke. Daher war das für mich anfangs nicht
wirklich verständlich: Wenn der Speicher im Adressraum des Prozesses
gamapped ist, dann wird doch wohl darauf zugegriffen!
Oder auch nicht? Vielleicht?
Der Compilerbauer kann in so einer Situation machen was er will: Auf
einer der letzten C++ Cons gab es einen netten Vortrag zu dem UB Thema:
https://www.youtube.com/watch?v=ehyHyAIa5so
Rolf M. schrieb:> char dient lediglich als Speicherplatz für ein Zeichen.
eben drum, wer sagt denn das Zeichen nicht über 127 gehen dürfen?
Wenn die Variable aber signed char ist geht char 128 eben nicht
Rolf M. schrieb:> dass man bei jeder Stringfunktion eine Warnung bekommt,> weil die Signedness nicht passt.
wie kommt man auf die Idee char signed zu definieren?
Joachim B. schrieb:> wie kommt man auf die Idee char signed zu definieren?
Weil es irrlevant ist. char (ohne signed / unsigned davor) ist nicht zum
Rechnen da, und ob der numerische Wert eines characters positiv oder
negativ ist, das ist Jacke wie Hose.
Hier wird immer von dem Zugriff geredet, aber bereits das Erzeugen des
Pointers ist problematisch:
6.5.6 Additive operators
When an expression that has integer type is added to or subtracted from
a pointer, the
result has the type of the pointer operand.
[...]
If both the pointer
operand and the result point to elements of the same array object, or
one past the last
element of the array object, the evaluation shall not produce an
overflow; otherwise, the
behavior is undefined.
Mikro 7. schrieb:> Das Verhalten bei einem out-of-bound Zugriff ist in C nicht definiert.
Dank der Äquivalenz von Zeiger und Arrayzugriffen, ist der Compiler
verpflichtet den Code zu generieren.
Das Verhalten zur Laufzeit, liegt dann in Gottes Hand.
Rolf M. schrieb:> char dient lediglich als Speicherplatz für ein Zeichen.> Da man mit Text nicht rechnet, ist die signedness egal.
Soweit nachvollziehbar. Hätten sie mal einen eigenen Datentyp für Bytes
vorgesehen...
Joachim B. schrieb:> wie kommt man auf die Idee char signed zu definieren?
ASCII hat nur 7 Bit, das obere Bit hat eine Sonderbedeutung (Parität,
Attribut, ...). Mit einem "signed char" kann man die Sonderbedeutung
recht schnell extrahieren.
Es ist eine idiotische Entscheidung, aber im Rahmen der damaligen
Technologie nachvollziehbar. Und heute haben wir Kompatiblität.
Joachim B. schrieb:> wie kommt man auf die Idee char signed zu definieren?
Bloss der Vollständigkeit halber: Im Gegensatz zu den den anderen "int"
Typen, gib es für char tatsächlich drei Varianten: char, signed char und
unsigned char.
Hier bspw. etwas zum Lesen (gibt aber bestimmt bessere Links):
https://stackoverflow.com/questions/2054939/is-char-signed-or-unsigned-by-defaultArduino Fanboy D. schrieb:> Mikro 7. schrieb:>> Das Verhalten bei einem out-of-bound Zugriff ist in C nicht definiert.>> Dank der Äquivalenz von Zeiger und Arrayzugriffen, ist der Compiler> verpflichtet den Code zu generieren.
Nö.
Joachim B. schrieb:> Letztens wieder mit Nokia Zeichensatz bis 255, isprint ignoriert alles> über 127
Woher soll der Compiler bzw. die Standardbibliothek auch wissen, welche
Zeichen sich hinter den Codes 128..255 der Nokia-Zeichencodierung
verbergen?
Je nach Umgebung kannst du die is*-Funktionen mittels
1
setlocale(LC_CTYPE,"...");
dazu bringen, auch andere 8-Bit-Zeichenkodierungen als den Default
(7-Bit-ASCII) zu akzeptieren, bspw. ISO 8859-x. Dann liefern isprint und
isalpha auch für Umlaute ein true zurück.
Joachim B. schrieb:> Rolf M. schrieb:>> char dient lediglich als Speicherplatz für ein Zeichen.>> eben drum, wer sagt denn das Zeichen nicht über 127 gehen dürfen?
Es sind Zeichen, keine Zahlen. Es gibt kein "über 127". Sieh es
einfach als einen Speicherblock, der (in dem Fall) 8 Bits breit ist. Wie
diese Bits interpretiert werden würden, wenn man damit rechen würde, ist
nicht von Belang. Daher ist auch nicht von Belang, ob man dafür einen
signed- oder unsigned-Typen verwendet. Text kennt kein Konzept einer
Signedness.
Wenn man char richtig verwendet, macht es für das Programm auch
keinerlei Unterschied.
> Rolf M. schrieb:>> dass man bei jeder Stringfunktion eine Warnung bekommt,>> weil die Signedness nicht passt.>> wie kommt man auf die Idee char signed zu definieren?
Wie kommt man darauf, es anders zu definieren? Alle anderen
Integer-Typen sind auch signed, wenn nichts explizit angegeben ist.
Rolf M. schrieb:> Sieh es> einfach als einen Speicherblock, der (in dem Fall) 8 Bits breit ist.
genau das ist doch das Problem, oder was sehe ich falsch?
#define GRAD 132
char text[3] = { "°C" }; (zur Ausgabe auf die Usart)
möchte ich Zeichen ersetzen zur Ausgabe auf das Display text[0]= GRAD
(entprechend Zeichensatz für Nokia) und GRAD liegt auf 132 ist es
ausserhalb 0-127 signed char.
An dieser Stelle habe ich mit der Arduino IDE offensichtlich mehr
Probleme als früher unter Atmel Studio auch mit gcc.
Witzig oder nicht, stellte ich letztens fest das die IDE sogar selber
umstellt
char text[4] = {"A°A"};
A°A gibt nicht etwa wie ich erwartet hätte in text[4]
text[0] = 65d;
text[1] = 132d;
text[2] = 65d;
text[3] = 0;
sondern irgendwie so
text[0] = 65d;
text[1] = 132d;
text[2] = große Zahl über 127 (ich glaube 176)
text[3] = 0;
Mal sieht die Printausgabe OK aus mal gibt es nur Quadrate, auch da
verstehe ich nicht warum mal ° und mal QUADRAT gezeigt wird.
Joachim B. schrieb:> A°A gibt nicht etwa wie ich erwartet hätte in text[4]>> text[0] = 65d;> text[1] = 132d;> text[2] = 65d;> text[3] = 0;>> sondern irgendwie so> text[0] = 65d;> text[1] = 132d;> text[2] = große Zahl über 127 (ich glaube 176)> text[3] = 0;
Ich soll dir von UTF-8 Grüße ausrichten.
Joachim B. schrieb:> möchte ich Zeichen ersetzen zur Ausgabe auf das Display text[0]= GRAD> (entprechend Zeichensatz für Nokia) und GRAD liegt auf 132 ist es> ausserhalb 0-127 signed char.
char ist dazu da, den Systenzeichensatz zu repräsentieren. Zwischen
0...127 ist dir ASCII garantiert, alle anderen Werte sind implementation
defined. Willst du einen anderen Zeichensatz verwenden, so benötigst du
einen anderen Typen als char und entsprechende Konvertierungsfunktionen.
Joachim B. schrieb:> Mal sieht die Printausgabe OK aus mal gibt es nur Quadrate, auch da> verstehe ich nicht warum mal ° und mal QUADRAT gezeigt wird.
'°' ist nicht in ASCII enthalten.
Das Problem ist da aber nicht die Signedness von char, sondern der
verwendete Zeichensatz. Die genannten 176 entsprechend dem Grad-Zeichen
im ISO-8859-1-Zeichensatz.
B. S. schrieb:> Joachim B. schrieb:>> möchte ich Zeichen ersetzen zur Ausgabe auf das Display text[0]= GRAD>> (entprechend Zeichensatz für Nokia) und GRAD liegt auf 132 ist es>> ausserhalb 0-127 signed char.>> char ist dazu da, den Systenzeichensatz zu repräsentieren.
Es ist der "execution character set" garantiert.
> Zwischen 0...127 ist dir ASCII garantiert, alle anderen Werte sind> implementation> defined. Willst du einen anderen Zeichensatz verwenden, so benötigst du> einen anderen Typen als char und entsprechende Konvertierungsfunktionen.
Wenn du mit "ASCII garantiert" meinst, dass alle ASCII Zeichen vorhanden
sind, dann stimmt das vielleicht. Ich habe bis jetzt nicht überprüft, ob
alle Zeichen vorhanden sind. Die Reihenfolge ist allerdings nicht
garantiert. ASCII kommt im Standard nur als Fußnote vor.
mh schrieb:> Wenn du mit "ASCII garantiert" meinst, dass alle ASCII Zeichen vorhanden> sind, dann stimmt das vielleicht. Ich habe bis jetzt nicht überprüft, ob> alle Zeichen vorhanden sind. Die Reihenfolge ist allerdings nicht> garantiert. ASCII kommt im Standard nur als Fußnote vor.
Habs gerade nachgelesen: Der Zeichensatz ist gemäss ASCII, die
Reihenfolge der Werte kann jedoch beliebig sein. Das Einzige was
garantiert ist, ist, dass alle ASCII-Zeichen vorzeichenlos in einen char
passen, die Werte der Zeichen
1
0123456789!"#%&'()*+,-./:;<=>?[\]^_{~}
aufsteigend ohne Lücke repräsentiert werden und dass '\0' == 0 ist.
Alles Andere ist implementation defined.
Rolf M. schrieb:> Das Problem ist da aber nicht die Signedness von char
Kann aber zum Problem werden, wenn man den kompletten Wertebereich von
256 Zeichen ausnutzen möchte. Leider existieren für die Repräsentation
eines signed Typen immer noch drei unterschiedliche Varianten (wobei
zugegeben fast nur das 2er-Komplement benutzt wird).
B. S. schrieb:> Das Einzige was> garantiert ist, ist, dass alle ASCII-Zeichen vorzeichenlos in einen char> passen, die Werte der Zeichen0123456789!"#%&'()*+,-./:;<=>?[\]^_{~}> aufsteigend ohne Lücke repräsentiert werden und dass '\0' == 0 ist.> Alles Andere ist implementation defined.
Das stimmt noch nicht ganz. Es müssen nur die Ziffern aufeinanderfolgend
sein.
Jemand schrieb:> Ich soll dir von UTF-8 Grüße ausrichten.
echt nicht hilfreich,
das geht die IDE nichts an was ich printe!
B. S. schrieb:> Joachim B. schrieb:>> Mal sieht die Printausgabe OK aus mal gibt es nur Quadrate, auch da>> verstehe ich nicht warum mal ° und mal QUADRAT gezeigt wird.>> '°' ist nicht in ASCII enthalten.
mag ja sein, mich stört das es mal funktioniert und mal NICHT, verstehst
du den Unterschied?
Rolf M. schrieb:> Die genannten 176 entsprechend dem Grad-Zeichen> im ISO-8859-1-Zeichensatz.
und da stört mich der Wechel, mal so mal so!
Rolf M. schrieb:> Das Problem ist da aber nicht die Signedness von char,
aber an anderer Stelle der str Funktionen.
B. S. schrieb:> Rolf M. schrieb:>> Das Problem ist da aber nicht die Signedness von char>> Kann aber zum Problem werden, wenn man den kompletten Wertebereich von> 256 Zeichen ausnutzen möchte
eben, auf µC wozu als Standard int16 verwenden? für 256 Zeichen -
Steuerzeichen.
Joachim B. schrieb:> Jemand schrieb:>> Ich soll dir von UTF-8 Grüße ausrichten.>> echt nicht hilfreich, [...]
Niemand hier kann etwas dafür, dass du char, string und Zeichencodierung
in C nicht verstehst.
Joachim B. schrieb:> Rolf M. schrieb:>> Das Problem ist da aber nicht die Signedness von char,>> aber an anderer Stelle der str Funktionen.
Die würden auch wunderbar für deinen Anwendungsfall funktionieren, mit
Ausnahme der is_XXX Funktionen. Du musst nur etwas flexibler sein. Auch
wenn "dein" Zeichensatz einem Zeichen einen Wert >127 zuordnet, kannst
du ihn mit einer C Implementation benutzen für die char==signed char
ist.
Joachim B. schrieb:> Jemand schrieb:>> Ich soll dir von UTF-8 Grüße ausrichten.>> echt nicht hilfreich,> das geht die IDE nichts an was ich printe!
Wenn du eine Textdatei bearbeitest, muss der Editor gezwungenermaßen
eine bestimmte Zeichenkodierung verwenden. Und deine IDE wird die
verwenden, auf die sie eingestellt ist.
Dazu kommt noch der C-Compiler und ggf. dessen Umkodierung vom Source
Character Set ins Execution Character Set.
Wenn das nicht zusammenpasst, kann schon mal Blödsinn rauskommen.
mh schrieb:> Das stimmt noch nicht ganz. Es müssen nur die Ziffern aufeinanderfolgend> sein.
Echt? Ich hatte den Paragraphen anders interpretiert.
Joachim B. schrieb:> mag ja sein, mich stört das es mal funktioniert und mal NICHT, verstehst> du den Unterschied?
Nennt sich implementation defined behaviour. Darauf kann man sich nur
auf einer spezifischen Plattform mit einer spezifischen Compilerversion
verlassen.
mh schrieb:> Du musst nur etwas flexibler sein
werde ich ja auch, da arbeite ich lieber mit memcpy statt mit str
Funktionen.
Dem memxxx ist es egal ob ich uint8_t verschiebe char oder unsigned
char.
Joachim B. schrieb:> Dem memxxx ist es egal ob ich uint8_t verschiebe char oder unsigned> char.
Den Stringfunktionen der Standardlibrary auch.
Der Compiler meckert bei der Übergabe, weil die Typen nicht
übereinstimmen.
Das kann man mit cast lösen, wenn man unbedingt unsigned char will und
den Compiler nicht umstellen will.
Denn du kannst dem Compiler sagen, ob char signed oder unsigned ist.
Dirk B. schrieb:> Denn du kannst dem Compiler sagen, ob char signed oder unsigned ist.
Damit bekommt man die Warnung bzgl. Zeiger aber nicht weg, weil char ein
anderer Typ ist als signed char (auch mit -fsigned-char) und ein anderer
als unsigned char (auch mit -funsigned-char).
Kurz: char, signed char und unsigned char sind 3 verschiedene Typen.
B. S. schrieb:> mh schrieb:>> Das stimmt noch nicht ganz. Es müssen nur die Ziffern aufeinanderfolgend>> sein.>> Echt? Ich hatte den Paragraphen anders interpretiert.
1
In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.
Und ein paar Zeilen vorher die "list of decimal digits"
Arduino Fanboy D. schrieb:> Mikro 7. schrieb:>> Das Verhalten bei einem out-of-bound Zugriff ist in C nicht definiert.>> Dank der Äquivalenz von Zeiger und Arrayzugriffen, ist der Compiler> verpflichtet den Code zu generieren.
Das ist schlicht falsch.
Joachim B. schrieb:>> Ich soll dir von UTF-8 Grüße ausrichten.> echt nicht hilfreich,> das geht die IDE nichts an was ich printe!
Aber den Editor.
Wenn du falsche Bytes in den Quelltext schreibst, dann kann der Compiler
da auch nix für. Eigene Selber-Schuld.
S. R. schrieb:> dann kann der Compiler> da auch nix für. Eigene Selber-Schuld.
auf das dünne Brett gehe ich noch nicht,
offensichtlich bin ich nicht verstanden worden,
wie schon geschrieben, mal printet der Atmel an der USART die richtige
Kombination für "°C" und ich kann das Zeichen "°" für das Display
erstzen, mal kommt eben Unfug heraus. Ich wollte nur wissen warum das so
ist, entweder die IDE ist schlau und kodiert passend um, warum dann
nicht immer, warum mal so mal so. Das nervt doch.
Ich kann mit allem leben wenn es konsequent ist, aber mal so mal so
ergibt für mich keinen passenden Ansatz richtig einzugreifen.
Joachim B. schrieb:> Ich kann mit allem leben wenn es konsequent ist, aber mal so mal so> ergibt für mich keinen passenden Ansatz richtig einzugreifen.
Wie wärs wenn du herausfindest was das Problem ist?
mh schrieb:> Wie wärs wenn du herausfindest was das Problem ist?
keine Sorge, da bin ich bei, nur manchmal gibts hier auch gute Tipps.
Mir die Schuld zuzuschieben ist leicht, hilft aber nicht wenn ein
Verhalten in der IDE inkonsequent ist.
Das macht die Analyse halt schwieriger.
"°C" druckt seriell einwandfrei, ich erkenne das ° und kann es zum
Display austauschen.
"A°A" eben nicht, das nachfolgende A ist im Eimer
Nop schrieb:> Das verhindert man, indem man sowas gar nicht erst schreibt,> sondern sich mal damit befaßt, was der C-Standard dazu meint.
Hat jemand mal die passende Stelle aus dem Standard, also die die sagt,
dass out-of-bounds access undefined behaviour ist?
Ich kenne nur die Stelle 6.5.2.1 "Array Subscripting":
"A postfix expression followed by an expression in square brackets [] is
a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the binary
+ operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2]
designates the E2-th element of E1 (counting from zero)."
Joachim B. schrieb:> char text[4] = {"A°A"};
Vorsicht!
Wenn die von deinem Editor/IDE verwendete Zeichencodierung UTF-8 ist,
was unter Linux Standard und auch unter Windows immer mehr im Kommen
ist, wird das °-Zeichen in zwei Bytes kodiert, d.h. in C ist
text[0] = 65
text[1] = 194
text[2] = 176
text[3] = 65
Die Nullterminierung wird unterschlagen, weil sie nicht in char[4] Platz
hat. Ein String ohne Nullterminierung führt zu beliebigen Problemen, die
auch zufälliger Art sein können (je nachdem, wie der Speicherinhalt
hinter der Variable test aussieht).
Damit sind wir sogar wieder ontopic :)
In C++ hingegen erhältst du die Fehlermeldung
1
initializer-string for array of chars is too long
Da wird einem wenigstens bewusst, dass das so nicht geht.
Joachim B. schrieb:> #define GRAD 132>> char text[3] = { "°C" }; (zur Ausgabe auf die Usart)>> möchte ich Zeichen ersetzen zur Ausgabe auf das Display text[0]= GRAD
Abgesehen von der zu kleinen Dimensionierung von text kannst du das 2
Bytes umfassende °-Zeichen nicht einfach mit einem 1-Byte-Zeichen
überschreiben, weil ja immer noch das zweite Byte stehen bleibt und als
ungültiges Zeichen (bspw. als leeres Quadrat) ausgegeben wird.
Christopher J. schrieb:> Hat jemand mal die passende Stelle aus dem Standard, also die die sagt,> dass out-of-bounds access undefined behaviour ist?
Nicht erst der Access ist UB, sondern schon die Erzeugung des Pointers,
der für diesen Access verwendet werden soll. Siehe hier:
Jemand schrieb:> 6.5.6 Additive operators
Christopher J. schrieb:> Nop schrieb:>> Das verhindert man, indem man sowas gar nicht erst schreibt,>> sondern sich mal damit befaßt, was der C-Standard dazu meint.>> Hat jemand mal die passende Stelle aus dem Standard, also die die sagt,> dass out-of-bounds access undefined behaviour ist?
Aus dem c11 draft N1570:
1
6.5.6 Additive operators
2
8 When an expression that has integer type is added to or subtracted from a pointer, the
3
result has the type of the pointer operand. If the pointer operand points to an element of
4
an array object, and the array is large enough, the result points to an element offset from
5
the original element such that the difference of the subscripts of the resulting and original
6
array elements equals the integer expression. In other words, if the expression P points to
7
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
8
(P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of
9
the array object, provided they exist. Moreover, if the expression P points to the last
10
element of an array object, the expression (P)+1 points one past the last element of the
11
array object, and if the expression Q points one past the last element of an array object,
12
the expression (Q)-1 points to the last element of the array object. If both the pointer
13
operand and the result point to elements of the same array object, or one past the last
14
element of the array object, the evaluation shall not produce an overflow; otherwise, the
15
behavior is undefined. If the result points one past the last element of the array object, it
16
shall not be used as the operand of a unary * operator that is evaluated.
Yalu X. schrieb:> Abgesehen von der zu kleinen Dimensionierung von text kannst du das 2> Bytes umfassende °-Zeichen nicht einfach mit einem 1-Byte-Zeichen> überschreiben, weil ja immer noch das zweite Byte stehen bleibt und als> ungültiges Zeichen (bspw. als leeres Quadrat) ausgegeben wird.
das war nur eiin Beispiel, selbst wenn die "Dimensionierung von text"
nicht zu klein ist kommts bei
"°C" richtig also das C an richtiger Stelle, während das "A°A" das letze
A eben nicht richtig kommt.
Aber gut ich prüfe das nochmal, weil ich normalerweise hinter "°C" nicht
mehr zugreife.
Wenn es doch passt dann ist mir mit einer 1 Byte längeren Hilfsvariable
ja gedient!
Dann kann ich um diese Besonderheit drum rum programmieren.
Es nervt halt nur wenn sich immer Nebenbaustellen auftun die mit der
Aufgabe nichts zu tun haben.
1. ist es gut das die IDE das automatisch berücksichtigt, also die
Ausgabe seriell von ° meistert.
2. Es war mein Fehler das ich nicht bemerkte das da nun 2 Zeichen für
°gebraucht werden.
3. ist es lösbar.
Also umsonst war der Thread nicht für mich und mit "element außerhalb
array" nicht mal OT
Christopher J. schrieb:> Ich kenne nur die Stelle 6.5.2.1 "Array Subscripting":
Das will hier keiner hören und sehen....
Arduino Fanboy wurde für blöd erklärt, und damit hat sichs dann.
Arduino Fanboy D. schrieb:> Christopher J. schrieb:>> Ich kenne nur die Stelle 6.5.2.1 "Array Subscripting":> Das will hier keiner hören und sehen....>> Arduino Fanboy wurde für blöd erklärt, und damit hat sichs dann.
Du hast bis jetzt nicht erklärt, wieso dieser Paragraph dazu führt, dass
es kein UB ist.
mh schrieb:> Du hast bis jetzt nicht erklärt, wieso dieser Paragraph dazu führt, dass> es kein UB ist.
Das dürfte ihm auch schwer fallen, wenn man den letzten Satz tatsächlich
mal liest:
"If both the pointer operand and the result point to elements of the
same array object, or one past the last element of the array object, the
evaluation shall not produce an overflow; otherwise, *the behavior is
undefined*."
Deutlicher geht's doch nicht.
mh schrieb:> Aus dem c11 draft N1570:6.5.6 Additive operators
[...]
Danke für den Hinweis. Da steht es tatsächlich Schwarz auf Weiß. Ich hab
mal ein kurzes Beispiel zusammengeklöppelt (bzw. zusammenkopiert), bei
dem der GCC ab Version 4.8 tatsächlich die Funktion "wegoptimiert":
1
#include<stdbool.h>
2
inttable[4]={1,2,3,4};
3
boolexists_in_table(intv)
4
{
5
// return true in one of the first 4 iterations or UB due to out-of-bounds access
6
for(inti=0;i<=4;i++){// "<=" is obviously wrong here
7
if(table[i]==v){returntrue;}
8
}
9
returnfalse;
10
}
wird mit dem GCC-ARM 8.2 mit -Os zu
1
exists_in_table(int):
2
mov r0, #1
3
bx lr
4
table:
5
.word 1
6
.word 2
7
.word 3
8
.word 4
D.h. der GCC liefert (mit -O2 oder -Os) bevorzugt eine "kaputte"
Funktion, die immer "true" zurückgibt, anstatt eine kaputte Funktion zu
liefern, die out-of-bounds Zugriff erlaubt. Dies ist mit -O0 oder -Og
nicht der Fall.
Verändert man jedoch die Zeile
1
if(table[i]==v){returntrue;}
zu
1
if(*(table+i)==v){returntrue;}
so ist es egal ob man mit -Og oder -O2 kompiliert. Der GCC liefert immer
den Code mit out-of-bounds Zugriff, d.h. für -O2
1
exists_in_table:
2
mov r3, #0
3
.L2:
4
cmp r3, #4
5
bgt .L6
6
ldr r2, .L7
7
ldr r2, [r2, r3, lsl #2]
8
cmp r2, r0
9
beq .L5
10
add r3, r3, #1
11
b .L2
12
.L6:
13
mov r0, #0
14
bx lr
15
.L5:
16
mov r0, #1
17
bx lr
18
.L7:
19
.word .LANCHOR0
20
table:
21
.word 1
22
.word 2
23
.word 3
24
.word 4
Andere Compiler die ich getestet habe (Clang, ICC) produzieren immer die
Funktion mit dem out-of-bounds Zugriff.
Wer damit rumspielen möchte:
https://godbolt.org/z/KJXize
PS:
Für diesen Fall (d.h. für "if (table[i]==v)...") gibt der GCC 8.2 gar
keine Warnung aus, nichtmal mit -Warray-bounds=2
Joachim B. schrieb:>> Wie wärs wenn du herausfindest was das Problem ist?>> keine Sorge, da bin ich bei, nur manchmal gibts hier auch gute Tipps.> Mir die Schuld zuzuschieben ist leicht, hilft aber nicht wenn ein> Verhalten in der IDE inkonsequent ist.
Das Verhalten in der IDE wird schon konsequent sein, die Frage ist, was
dein Betriebssystem mit der IDE anstellt. Zeichencodierung ist ein
ziemlich tiefes Loch...
Wenn du das komplett umgehen willst, dann nutze in deinem Quelltext
einfach nur ASCII-Zeichen:
1
charstr[]=" \xB0C";
Damit ist dein String garantiert und immer iso8859-1 codiert. Wenn
dein serielles Terminalprogramm nun UTF-8 benutzt, wird es etwas
falsches anzeigen.
Oder du codierst explizit UTF-8:
1
charstr[]=" \xC2\xB0C";
Damit ist dein String garantiert und immer utf-8 codiert. Wenn dein
serielles Terminalprogramm nun iso8859-1 benutzt, wird es etwas falsches
anzeigen. Außerdem eignet sich utf-8 für einfach LCDs weniger gut als
ein passender 8-bittiger Zeichensatz.
> Das macht die Analyse halt schwieriger.>> "°C" druckt seriell einwandfrei, ich erkenne das ° und kann es zum> Display austauschen.> "A°A" eben nicht, das nachfolgende A ist im Eimer
Du kannst ja mal statt der einzelnen Zeichen deren Hexwerte ausgeben.
Dann solltest du recht schnell sehen, welche Bytes da nun über den Draht
gehen.
S. R. schrieb:> Du kannst ja mal statt der einzelnen Zeichen deren Hexwerte ausgeben.
hatte ich doch!
Beitrag "Re: Auf element außerhalb array zugreifen"
ob nun hex oder dez ist doch egal.
S. R. schrieb:> Wenn du das komplett umgehen willst, dann nutze in deinem Quelltext> einfach nur ASCII-Zeichen:char str[] = " \xB0C";
macht den Quelltext nicht gerade lesbarer.
Joachim B. schrieb:>> Wenn du das komplett umgehen willst, dann nutze in deinem Quelltext>> einfach nur ASCII-Zeichen:char str[] = " \xB0C";>> macht den Quelltext nicht gerade lesbarer.
Aber dafür wenigstens unabhängig von deinem Editor. Du darfst das auch
gerne hinter einem #define verstecken, wenn du möchtest.
Die Alternative wäre, dass du tatsächlich sowas wie "Text-Rendering"
implementierst, dein Programm also tatsächlich weiß, was es auf das
Display schreibt. Für kleine Controller in der westlichen Welt ist das
vermutlich übertrieben, aber das wäre der richtige Weg...
S. R. schrieb:> aber das wäre der richtige Weg...
der einfachste, bequemste (und ganz richtige) Weg wäre - zumindest
wenn man GCC benutzt - dessen Fähigkeiten auszunutzen:
-finput-charset=<input charset>
-fexec-charset=<exec charset>
Wenn man seine Quelltext beispielsweise in utf-8 schreibt, der µC aber
nur ISO 8859-1/Latin 1 bietet, kommt ersteres in <input charset> und
letzteres in <exec charset>.
GCC sorgt dann (mithilfe von iconv) wie von Zauberhand selbst dafür, daß
die richtigen Zeichen im binary landen.
S. R. schrieb:> Aber dafür wenigstens unabhängig von deinem Editor. Du darfst das auch> gerne hinter einem #define verstecken, wenn du möchtest.
du meinst so?
#define GRAD_CELSIUS "\xB0C"
strcat(str_ausgabe, GRAD_CELSIUS);
ja kann man machen
Markus F. schrieb:> der einfachste, bequemste (und ganz richtige) Weg wäre - zumindest> wenn man GCC benutzt - dessen Fähigkeiten auszunutzen:> -finput-charset=<input charset>> -fexec-charset=<exec charset>>> Wenn man seine Quelltext beispielsweise in utf-8 schreibt, der µC aber> nur ISO 8859-1/Latin 1 bietet, kommt ersteres in <input charset> und> letzteres in <exec charset>.>> GCC sorgt dann (mithilfe von iconv) wie von Zauberhand selbst dafür, daß> die richtigen Zeichen im binary landen.
auch ein interessanter Weg, wäre nur zu klären mit was der Quelltext
Editor arbeitet, aber ich verstehe nicht was der µC damit zu tun hat,
der bietet mir erst mal kein "der µC aber nur ISO 8859-1/Latin 1 bietet"
Der Weg ist interessant aber mir zu hoch, ich gestehe.
Ich habe auch nicht unbedingt große Lust in der IDE rumzufummeln.
Da gibt es leichtere Wege zum gewünschten Ergebnis zu kommen.
Ich denke ich werde im Quelltext "*C" schreiben und den "*" beim
Vorkommen von "*C" tauschen gegen das Zeichen "°" für das Display. Ist
dann halt so.
Joachim B. schrieb:> Ich habe auch nicht unbedingt große Lust in der IDE rumzufummeln.> Da gibt es leichtere Wege zum gewünschten Ergebnis zu kommen.
Meinst du das ernst? Du begehst lieber schwere Verbrechen gegen die
Lesbarkeit deines Quelltextes, als 5 Minuten zu investieren, um deine
IDE richtig einzustellen?
Joachim B. schrieb:> auch ein interessanter Weg, wäre nur zu klären mit was der Quelltext> Editor arbeitet, aber ich verstehe nicht was der µC damit zu tun hat,> der bietet mir erst mal kein "der µC aber nur ISO 8859-1/Latin 1 bietet"
Dem µC ist das auch egal - aber dir nicht. Denn du möchtest ja das
°-Zeichen haben.
Welchen Code benutzt das Display (wenn vorhanden)?
Welchen Code benutzt das Terminal(programm), das am UART hängt?
(Kann man das evtl. einstellen)
Welchen Code benutzt der Editor/IDE?
(Kann man das evtl. auch einstellen, UTF-8 wäre ok, wenn du das im Griff
hast.)
mh schrieb:> Meinst du das ernst? Du begehst lieber schwere Verbrechen gegen die> Lesbarkeit deines Quelltextes
na ja das ist geklärt wie man das verständlich und lesbar hinbekommt!
übertreib mal nicht so!
mh schrieb:> als 5 Minuten zu investieren, um deine> IDE richtig einzustellen?
solange die IDE schneller wechseln als ich meine Rechner werde ich doch
nicht IDE umzustellen, es gibt Wichtigeres zu tun.
Informatiker und Dauerprogger mögen das IDE Umstellen doch leicht
finden, für mich ist das ein blöde Nebenbaustelle ohne zu wissen was man
damit auslöst. Ist ja nicht das erste Mal und nicht nur bei mir das wer
irgendwie um OS Eigenheiten oder Sonstiges schmutzige HACKs anwenden
muss. Über Patches statt Fehlerbehebung hast du bestimmt schon gelesen.
Joachim B. schrieb:> werde ich doch> nicht IDE umzustellen, es gibt Wichtigeres zu tun
Wenn das ach so Wichtige nicht mal soviel Raum läßt, zwei (!!)
Compileroptionen zu setzen, warum hast Du dann überhaupt gefragt?
Daß das Problem bloß durch darüber reden weggeht. hast Du doch sicher
nicht ernsthaft erwartet, oder?
Markus F. schrieb:> Wenn das ach so Wichtige nicht mal soviel Raum läßt, zwei (!!)> Compileroptionen zu setzen, warum hast Du dann überhaupt gefragt?
Normalerweise würde ich dir recht geben, dass das Setzen von
Compileroptionen kein Hindernis sein sollte. Allerdings finde ich
Quellcode, welcher nur mit einem bestimmten Zeichensatz korrekt
kompilierbar ist, nicht so schön.
Es gibt aber die Möglichkeit, String-Literale als UTF8/16/32 anzulegen,
welche dann unabhängig von der Kodierung des Quellcodes (solange diese
dem Compiler richtig mitgeteilt wird; fast immer UTF-8) immer den
richtigen Zeichensatz im Programm haben:
https://en.cppreference.com/w/c/language/string_literal
In C ist das leider nicht besonders nützlich. In C++ hingegen kann man
solche Literale vom Compiler, während des Kompilierens, in einen
beliebigen Zeichensatz (inkl. selbstdefinierte) transformieren, sodass
das umgewandelte Ergebnis im Flash-Speicher landet und der Code dennoch
lesbar bleibt.
Im Anhang ist ein Beispiel dazu. Da der AVR-GCC ja leider keine
C++-Standard-Bibliothek mitliefert muss man (ziemlich hässlich) ein paar
Standard-Hilfsklassen selbst definieren. Der Code ist zum Testen aber
auch auf dem PC lauffähig.
Einen latin1-String kann man damit so definieren:
1
constexprautostr1PROGMEM=asLatin1(U"UE = Ü, OE = Ö, GRAD = °, SS = ß, Yen = ¥");
Diesen auszugeben und als Latin1 zu interpretieren sieht dann z.B. so
aus:
1
U E = Ü , O E = Ö , G R A D = °...
2
55 45 20 3d 20 dc 2c 20 4f 45 20 3d 20 d6 2c 20 47 52 41 44 20 3d 20 b0...
Die Konvertierung Unicode->Latin1 ist zum Glück einfach, da die Zeichen
128-255 (fast?) identisch sind. Die gezeigte Ausgabe sollte immer
identisch sein, egal wie der Quelltext kodiert ist, solange der Compiler
die Kodierung des Quelltexts kennt. Bei IDEs sollte das ja eigentlich
immer automatisch korrekt sein.
Das Ganze funktioniert auch mit Arduino, welches ja sowieso schon C++
benutzt.
Markus F. schrieb:> Wenn das ach so Wichtige nicht mal soviel Raum läßt, zwei (!!)> Compileroptionen zu setzen, warum hast Du dann überhaupt gefragt?
weil ich die Problematik zuerst nicht verstand und mir Aufklärung
erhoffte die ja auch gekommen ist.
> Daß das Problem bloß durch darüber reden weggeht. hast Du doch sicher> nicht ernsthaft erwartet, oder?
nö aber es hat mir gezeigt wie ich damit umgehen möchte.
Statt ständig irgendwelche Nokia Zeichensätze in LIBs zu optimieren oder
korrigieren, an IDEs rumpatchen oder ähnliches kümmere ich mich um was
ich besser kann, löten z.B. 10µF an ESP32 von EN zu GND
Dr. Sommer schrieb:> Allerdings finde ich> Quellcode, welcher nur mit einem bestimmten Zeichensatz korrekt> kompilierbar ist, nicht so schön.
Du kannst -finput-charset (meist) auch weglassen, dann findet GCC den
auch aufgrund der Locale-Einstellung selber raus.
P.S.: ... und was TMP angeht, bin ich seit Jahren zwischen
"beeindruckend, was da alles geht" und "brrrrr, diese Syntax" hin- und
hergerissen.
Joachim B. schrieb:> Ich denke ich werde im Quelltext "*C" schreiben> und den "*" beim Vorkommen von "*C" tauschen gegen> das Zeichen "°" für das Display. Ist dann halt so.
Du tust mir Leid. Nimm wenigstens ein Zeichen, was du sonst nirgends
benutzt und definiere das für dich um, z.B. '}', '$' oder '`'. Das ist
dann zwar genauso hirntot, braucht aber weniger grässlichen Code drum
herum.
Markus F. schrieb:> Du kannst -finput-charset (meist) auch weglassen, dann findet GCC den> auch aufgrund der Locale-Einstellung selber raus.
Ja. Leider funktioniert das nur bei ASCII-kompatiblen Zeichensätzen.
Wenn man z.B. den Code als UTF-16 kompiliert, kann man die
Standard-Header nicht mehr inkludieren, weil die ASCII sind... Das ist
das Witz an den Literalen mit Zeichensatz-Angabe (U"blub") - egal
welchen Zeichensatz der Code hat, das kompilierte Programm sieht nur
Text im gewünschten Zeichensatz (hier: UTF-32). Einen ganz ähnlichen
Trick kann man machen, um die UTF-16-Little-Endian-Strings für
USB-Deskriptoren zu generieren, ohne den Sourcecode auf UTF-16 umstellen
zu müssen (was genanntes Header-Problem bewirken würde).
Markus F. schrieb:> P.S.: ... und was TMP angeht, bin ich seit Jahren zwischen> "beeindruckend, was da alles geht" und "brrrrr, diese Syntax" hin- und> hergerissen.
Ja die ganze C++-Syntax ist nicht so schön. Sie sollte halt
abwärtskompatibel zu C sein. Dafür kann man Dinge schön in Bibliotheken
kapseln und dann hübsche APIs bauen, wie die gezeigte asLatin1-Funktion.
Joachim B. schrieb:> du meinst so?> #define GRAD_CELSIUS "\xB0C"> strcat(str_ausgabe, GRAD_CELSIUS);
so ganz geht das so nicht.
die Escapesequenz \x ist gierig. Die nimmt alle folgenden Hexziffern.
Da das C auch dazugehört wird es noch mit umgewandelt.
In C kann man auch Stringliterale aneinander ketten:
Dirk B. schrieb:> so ganz geht das so nicht.>> die Escapesequenz \x ist gierig. Die nimmt alle folgenden Hexziffern.> Da das C auch dazugehört wird es noch mit umgewandelt.>> In C kann man auch Stringliterale aneinander ketten:> #define GRAD "\xB0"> sprintf(str_ausgabe, "%.1f"GRAD"C", temp);
danke hilfreich und konstruktiv!
Joachim B. schrieb:>> sprintf(str_ausgabe, "%.1f"GRAD"C", temp);>> danke hilfreich und konstruktiv!
Und das kann man auch noch leserlicher gestalten, indem man WS
einstreut:
1
printf("%.1f"GRAD"C\n",22.5);
Dieser wird einfach entfernt. I.e. sehr nuetzlich, um lange Strings zu
definieren.
leo
Joachim B. schrieb:> mh schrieb:>> als 5 Minuten zu investieren, um deine>> IDE richtig einzustellen?>> solange die IDE schneller wechseln als ich meine Rechner werde ich doch> nicht IDE umzustellen, es gibt Wichtigeres zu tun.
Gut, wenn du lieber umständliche und unschöne Verrenkungen in deinem
Code einbaust, um zu vermeiden, eine simple Einstellung anzupassen,
kannst du das ja gerne tun. Dann brauchst du dich aber nicht darüber
beschweren, dass du umständliche und unschöne Verrenkungen brauchst,
damit es so tut, wie du willst.
S. R. schrieb:> Joachim B. schrieb:>> Ich denke ich werde im Quelltext "*C" schreiben>> und den "*" beim Vorkommen von "*C" tauschen gegen>> das Zeichen "°" für das Display. Ist dann halt so.>> Du tust mir Leid. Nimm wenigstens ein Zeichen, was du sonst nirgends> benutzt und definiere das für dich um, z.B. '}', '$' oder '`'. Das ist> dann zwar genauso hirntot, braucht aber weniger grässlichen Code drum> herum.
OK, ich bin hirntot, habe aber meine Lösung gefunden
Oh graus, wie furchtbar... Macht es dich irgendwie an 100x
"menu[HAUPT_SCREEN][linecounter]" zu schreiben? Sind temporäre Variablen
irgendwie verboten? Dazu noch die vermurkste Einrückung, sinnloses
mehrfaches Aufrufen von strchr und strlen... Wie wäre es damit:
Ganz davon abgesehen dass das nur funktioniert wenn nur ein einziges
Gradzeichen da ist und dieses ganz am Anfang steht (wozu dann strchr?).
Was der Blödsinn mit dem Prozentzeichen soll weiß wohl keiner. Und was
ist "HAUPT_SCREEN" für ein tolles Denglisch?
Dr. Sommer schrieb:> Oh graus, wie furchtbar... Macht es dich irgendwie an 100x> "menu[HAUPT_SCREEN][linecounter]" zu schreiben? Sind temporäre Variablen> irgendwie verboten?
keine Ahnung was die ARDUINO IDE so im Detail treibt
in AVR Studio hätte ich das sicher anders geschrieben, aber mir geht der
SRAM aus, nein es macht mich nicht an öfter
"menu[HAUPT_SCREEN][linecounter]" zu schreiben, aber es funktioniert,
ist ja nur im Source und ich kannka auch c&p, als wer das öfter schreibt
hat Compi eh nicht verstanden.
> Dazu noch die vermurkste Einrückung,
Ist auch nicht auf meinen Mist gewachsen aber in der IDE nützlich und
hier im Forum quäle ich mich immer das richtig einzufügen.
> sinnloses mehrfaches Aufrufen von strchr und strlen... Wie wäre es damit:
schaue ich mir gerne an, gegen konstruktive Kritik habe ich nichts, kann
ja nur dazulernen
> Ganz davon abgesehen dass das nur funktioniert wenn nur ein einziges> Gradzeichen da ist und dieses ganz am Anfang steht (wozu dann strchr?).
Es ist nur ein einzelnes GRAD Zeichen auf dem Nokia Display, deswegen
strchr, also erst mal in der Zeile suchen (war so eine Idee um mich
nicht auf den Platz festzulegen, aber du hast Recht ich schreibe ab
pos12 Serial.print raus weil es da nun mal ist.
Ich hätte auch strrchr nehmen können, witzigerweise ist das nicht
C-Standard jedenfalls in meinem GCC, hatte ich nachgebaut, Quellen für
strrchr gibts ja c-konform im Netz.
> Was der Blödsinn mit dem Prozentzeichen soll weiß wohl keiner.
muss das einer wissen? hätte ich hier auch rausnehmen können, aber nun
gut wer neugierig ist soll belohnt werden % für den DHT22 humidity
und da alle = Zeichen untereinander stehen (sollen) aber % ein Zeichen
kürzer ist als °C braucht es hinter % noch ein SPACE
Und was
> ist "HAUPT_SCREEN" für ein tolles Denglisch?
wenns dich stört kann man es auch zu "MAIN_SCREEN" oder "HAUPT_BILD"
umbenennen, wer weiter keine Sorgen hat muss glücklich sein.
Joachim B. schrieb:> in AVR Studio hätte ich das sicher anders geschrieben
Das benutzt doch den selben Compiler (AVR-GCC)...
Joachim B. schrieb:> aber mir geht der> SRAM aus,
was hat das damit zu tun? Die Variable wird selbstverständlich
wegoptimiert bzw. in ein Register gelegt. Es könnte sogar effizienter
werden, wenn "menu" ein Zeiger ist.
Joachim B. schrieb:> aber es funktioniert,
Ist aber furchtbar zu lesen. Man muss ständig gucken ob das wirklich
jedes Mal das Gleiche ist. Merke: Code wird 1x geschrieben und 100x
gelesen..
Joachim B. schrieb:> als wer das öfter schreibt> hat Compi eh nicht verstanden.
Äh, was? Wer öfter den selben Code schreibt, macht was falsch! Der
Compiler hilft dir dabei, Wiederholungen zu vermeiden, insbesondere in
C++ (Arduino). Das Prinzip heißt "DRY" (don't repeat yourself). Wenn du
den Ausdruck ändern willst, musst du ihn sonst überall ändern. Außerdem,
warum immer das &? Warum manchmal der cast auf char*, manchmal nicht?
Inkonsistent!
Joachim B. schrieb:> aber in der IDE nützlich
In welcher IDE ist falsche Einrückung nützlich?
Joachim B. schrieb:> hier im Forum quäle ich mich immer das richtig einzufügen.
Einfach Copy&Paste. Die Forensoftware macht das automatisch richtig,
wenn man code-Tags nutzt.
Joachim B. schrieb:> Ich hätte auch strrchr nehmen können, witzigerweise ist das nicht> C-Standard
Doch.
Joachim B. schrieb:> witzigerweise ist das nicht> C-Standard jedenfalls in meinem GCC
Dann stimmt mit dem irgendwas nicht.
Warum iterierst du nicht einfach den String Zeichen für Zeichen, gibst
Grad-Zeichen umgewandelt aus und den Rest so wie er ist? Dann kannst du
eine beliebige Anzahl Grad-Zeichen umwandeln.
Joachim B. schrieb:> und da alle = Zeichen untereinander stehen (sollen) aber % ein Zeichen> kürzer ist als °C braucht es hinter % noch ein SPACE
Dann sollte man das genau an der Stelle platzieren, an der man auch das
% einfügt. Und nicht irgendwann später prüfen ob da ein % ist. Stell dir
vor du willst später noch irgendeinen anderen prozentualen Wert
ausgeben. Dann wunderst du dich warum da plötzlich ein Leerzeichen
erscheint...
Dr. Sommer schrieb:> Joachim B. schrieb:>> in AVR Studio hätte ich das sicher anders geschrieben>> Das benutzt doch den selben Compiler (AVR-GCC)...
du weisst aber das es da verschiedene Versionen gibt?
Die Behauptung alles GCC ist zwar richtig aber nicht zielführend bei
unterschiedlichen Versionen!
> Joachim B. schrieb:>> aber mir geht der>> SRAM aus,>> was hat das damit zu tun? Die Variable wird selbstverständlich> wegoptimiert bzw. in ein Register gelegt. Es könnte sogar effizienter> werden, wenn "menu" ein Zeiger ist.
Ich bemerke halt Seiteneffekte und kämpfe noch mit Zeiger, das habe ich
zugegeben noch nicht vollständig verstanden, ich weiss zwar das ein
Array char zeiger[] ein Zeiger ist, aber wenn ich denüber 2 Funktinen
weiterleiten will meckert der Compiler immer, wann dereferenziert man
und wann nicht?
> Joachim B. schrieb:>> aber es funktioniert,>> Ist aber furchtbar zu lesen. Man muss ständig gucken ob das wirklich> jedes Mal das Gleiche ist. Merke: Code wird 1x geschrieben und 100x> gelesen..
oh ich schreibe Code auch öfter, ich lerne täglich dazu und was bei
einem Compiler gcc in der Arduino IDE mal funktionierte:
char *var_ptr = NULL;
var_ptr = malloc(10);
wird im ESP32 Compiler angemeckert!
const char* zu char*
das soll jemand verstehen....
der eine macht strxxx Funktionen zu unsigned char der andere zu char und
einer meckert IMMER
> Joachim B. schrieb:>> als wer das öfter schreibt>> hat Compi eh nicht verstanden.>> Äh, was? Wer öfter den selben Code schreibt, macht was falsch!
mache ich doch nicht das öfter schreiben, lies mal genauer
> Der Compiler hilft dir dabei, Wiederholungen zu vermeiden, insbesondere in> C++ (Arduino). Das Prinzip heißt "DRY" (don't repeat yourself). Wenn du> den Ausdruck ändern willst, musst du ihn sonst überall ändern.
auch da gibt es suchen & ersetzen, nützlich wenn man es kennt
> Außerdem, warum immer das &? Warum manchmal der cast auf char*, manchmal nicht?> Inkonsistent!
weil es irgendwann wo klemmte, soll ich mich wiederholen?
nun habe ich es ja auch stellenweise ohne &, kommt halt drauf an ob ich
aufs 0te Element zugreifen will oder nicht.
> Joachim B. schrieb:>> aber in der IDE nützlich>> In welcher IDE ist falsche Einrückung nützlich?
falsch ist deiner Meinung nach was du hier siehst, Forum != IDE Editor
> Joachim B. schrieb:>> hier im Forum quäle ich mich immer das richtig einzufügen.>> Einfach Copy&Paste. Die Forensoftware macht das automatisch richtig,> wenn man code-Tags nutzt.
nutze ich, aber weil ich nicht jedesmal händich das Editorfenster
anfassen will an verschiedenen Compis, sitzt du immer vor demselben
Compi mit 32" Monitor?
> Joachim B. schrieb:>> Ich hätte auch strrchr nehmen können, witzigerweise ist das nicht>> C-Standard>> Doch.
dann eben nicht in jedem Compiler implementiert!
Mag sein das du Ahnung hast, aber nicht überall
> Joachim B. schrieb:>> witzigerweise ist das nicht>> C-Standard jedenfalls in meinem GCC>> Dann stimmt mit dem irgendwas nicht.>> Warum iterierst du nicht einfach den String Zeichen für Zeichen, gibst> Grad-Zeichen umgewandelt aus und den Rest so wie er ist? Dann kannst du> eine beliebige Anzahl Grad-Zeichen umwandeln.
Einen Parser hatte ich mal vor 30 Jahren geschrieben für die Umwandlung
von Quelltext PC1500 in Tokens die mit bin2wav geschriebe werden
konnten.
Heute beschäftigt mich eher anderes.
> Joachim B. schrieb:>> und da alle = Zeichen untereinander stehen (sollen) aber % ein Zeichen>> kürzer ist als °C braucht es hinter % noch ein SPACE>> Dann sollte man das genau an der Stelle platzieren, an der man auch das> % einfügt. Und nicht irgendwann später prüfen ob da ein % ist. Stell dir> vor du willst später noch irgendeinen anderen prozentualen Wert> ausgeben. Dann wunderst du dich warum da plötzlich ein Leerzeichen> erscheint...
ja sowas passiert mir ab und an mal bei "meiner" Art der Programmierung,
aber ich bin halt eher Hardwareman und lerne an so vielen Baustellen,
darf aber auch das Ziel nicht aus den Augen verlieren, will ich das
Projekt zum Laufen bekommen oder nur der perfekte Progger werden, aber
das Projekt läuft nie?
trotzdem danke für konstruktive Tipps, ich kann bestimmt davon was
mitnehmen und umsetzen.
Joachim B. schrieb:> du weisst aber das es da verschiedene Versionen gibt?
Ach, ich dachte es gibt nur die Version 8.2.0. ... Die sind ziemlich
abwärtskompatibel. C++03 und C99 sollten mit Arduino und Atmel Studio zu
98% identisch gehen, bis auf kleine Verbesserungen beim Optimizer.
Joachim B. schrieb:> ich weiss zwar das ein> Array char zeiger[] ein Zeiger ist
Ein Array ist ein Array und kein Zeiger. Es wird zu einem Zeiger wenn
man es übergibt oder zuweist, wie in meinem Beispiel mit der "m"
Variable.
Joachim B. schrieb:> aber wenn ich denüber 2 Funktinen> weiterleiten will meckert der Compiler immer
Hä? Zeigen. Zeiger kann man beliebig oft übergeben.
Joachim B. schrieb:> wann dereferenziert man> und wann nicht?
Man dereferenziert nur genau dann, wenn man das Ziel des Zeigers lesen
oder schreiben will.
Joachim B. schrieb:> char *var_ptr = NULL;> var_ptr = malloc(10);>> wird im ESP32 Compiler angemeckert!
Wenn das ein C Compiler ist, glaube ich das nicht. Der Fehler liegt
woanders. Wenn es C++ ist (z.B. Arduino), dann muss da noch ein Cast
hin:
1
var_ptr=static_cast<char*>(malloc(10));
wobei man in C++ sowieso lieber "new" nutzen sollte
1
var_ptr=newchar[10];
Was aber leider beim AVR-GCC wohl nicht geht. Beim ESP vielleicht schon,
kA.
Joachim B. schrieb:> der eine macht strxxx Funktionen zu unsigned char der andere zu char und> einer meckert IMMER
Was? Die Standard-C-String-Funktionen nutzen alle char* bzw. const
char*.
Joachim B. schrieb:> auch da gibt es suchen & ersetzen, nützlich wenn man es kennt
Nein, das gibt eine Katastrophe, wenn man zu viel ersetzt. Code muss man
so schreiben, dass man Suchen & Ersetzen so gut wie nie braucht. Da du
offenbar Anfänger bist, kannst du das den erfahreneren Programmierern
ruhig glauben...
Joachim B. schrieb:> weil es irgendwann wo klemmte, soll ich mich wiederholen?
Ja, zeige die exakte Stelle an er es klemmen soll.
Joachim B. schrieb:> nun habe ich es ja auch stellenweise ohne &, kommt halt drauf an ob ich> aufs 0te Element zugreifen will oder nicht.
& braucht man bei Arrays fast nie. Wenn du einen Zeiger auf das 7.
Element brauchst, kannst du
1
&array[7]
machen, aber
1
array+7
ist viel schöner. Wenn man einen Zeiger auf das 0. Element braucht,
reicht einfach "array". In meinem abgewandelten Code ist nirgendwo ein
"&" oder ein Cast!
Joachim B. schrieb:> falsch ist deiner Meinung nach was du hier siehst, Forum != IDE Editor
Dass schlecht eingerückter Code schlecht ist, ist allgemeiner Konsens.
Auch im Forum darf man anderen Teilnehmern das Lesen erleichtern, indem
man korrekt einrückt. Das ist, wie gesagt, dank Copy&Paste überhaupt
kein Problem. Hast du den Code fürs Forum extra zerstückelt? Dein Code
sieht aus, als würde er ganz anders funktionieren, als er tatsächlich
ist! Da fehlen ein paar { und }, um ihn so funktionieren zu lassen, wie
er aussieht.
Du schreibst:
Also etwas komplett anderes. Das ist sehr gefährlich - in 2 Monaten
stolperst du selbst darunter.
Joachim B. schrieb:> nutze ich, aber weil ich nicht jedesmal händich das Editorfenster> anfassen will an verschiedenen Compis, sitzt du immer vor demselben> Compi mit 32" Monitor?
Was ist ein "Compi"? Ein Compiler? Seit wann haben Compiler Monitore?
Tippst du den Code vom einem Computer fehlerhaft an den anderen Computer
ab? Warum kopierst du ihn nicht per USB-Stick, Netzwerk, Dropbox, ...
Joachim B. schrieb:> dann eben nicht in jedem Compiler implementiert!
Dann ist das kein C(++)-Compiler. Außerdem ist das wenn schon in der
Standardbibliothek implementiert. Hab gerade ausprobiert, mit Arduino
gehts.
Joachim B. schrieb:> Einen Parser hatte ich mal vor 30 Jahren geschrieben für die Umwandlung> von Quelltext PC1500 in Tokens die mit bin2wav geschriebe werden> konnten.
Das ist so simpel, dass das kaum den Begriff "Parser" verdient. Einfach
nur eine olle Schleife... Wäre auch noch besser lesbar als deine
verschachtelte Logik die nur in Spezialfällen funktioniert...
Joachim B. schrieb:> will ich das> Projekt zum Laufen bekommen oder nur der perfekte Progger werden, aber> das Projekt läuft nie?
Wenn du schon im Forum die Experten fragst, kannst du auch den Rat
annehmen...
Joachim B. schrieb:>> Du tust mir Leid. Nimm wenigstens ein Zeichen, was du sonst nirgends>> benutzt und definiere das für dich um, z.B. '}', '$' oder '`'. Das ist>> dann zwar genauso hirntot, braucht aber weniger grässlichen Code drum>> herum.>> OK, ich bin hirntot, habe aber meine Lösung gefunden
Deine Lösung ist hirntot, nicht du.
> Serial.print("°"); Serial.println("C|");
Uuund: Wieder hast du eine Abhängigkeit vom Zeichensatz des Quelltextes
zum Zeichensatz des Displays. Wieder nix gelernt, den gleichen Fehler
wieder gemacht. Gratuliere.
Dr. Sommer schrieb:> Joachim B. schrieb:>> aber wenn ich denüber 2 Funktinen>> weiterleiten will meckert der Compiler immer>> Hä? Zeigen. Zeiger kann man beliebig oft übergeben.
char var[] = {"huhu"};
void func1(char *);
void func2(char *);
func1(var); // bis hier kam ich ja im C-Kurs noch mit
aber dann wenn func1 func2 aufruft
klappt bei mir nie, egal ob mit cast oder nicht
dabei sollte doch einfach immer nur eine Adresse weitergereicht werden,
die Adresse vom char ARRAY
> Joachim B. schrieb:>> wann dereferenziert man>> und wann nicht?>> Man dereferenziert nur genau dann, wenn man das Ziel des Zeigers lesen> oder schreiben will.
so lernte ich das? aber wenn func1 func2 aufruft warum klappt das nicht?
> Joachim B. schrieb:>> char *var_ptr = NULL;>> var_ptr = malloc(10);>>>> wird im ESP32 Compiler angemeckert!>> Wenn das ein C Compiler ist, glaube ich das nicht. Der Fehler liegt> woanders. Wenn es C++ ist (z.B. Arduino), dann muss da noch ein Cast> hin:
nee genau anders rum, im Arduino unter #if defined(_AVR_) klappt
char *var_ptr = NULL;
var_ptr = malloc(10);
1
voidsetup(){
2
#if defined (ESP32)
3
#pragma message "ESP32"
4
#elif defined (__AVR__)
5
#pragma message "AVR"
6
#endif
7
8
char*var_ptr=NULL;
9
var_ptr=malloc(10);
10
}
11
12
voidloop(){
13
// put your main code here, to run repeatedly:
14
15
}
16
17
/*
18
ergibt:
19
20
D:\atmel\__ARDUINO__\char_var\char_var.ino: In function 'void setup()':
Der Sketch verwendet 444 Bytes (1%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
25
Globale Variablen verwenden 9 Bytes (0%) des dynamischen Speichers, 2039 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
26
*/
> Was? Die Standard-C-String-Funktionen nutzen alle char* bzw. const> char*.
siehst du auch du schreibst bzw. also ODER
> Da du> offenbar Anfänger bist, kannst du das den erfahreneren Programmierern> ruhig glauben...
was proggen angeht bin ich Einäugiger unter Blinden
> Joachim B. schrieb:>> nun habe ich es ja auch stellenweise ohne &, kommt halt drauf an ob ich>> aufs 0te Element zugreifen will oder nicht.>> & braucht man bei Arrays fast nie. Wenn du einen Zeiger auf das 7.> Element brauchst, kannst du
bei mehrdimensionalen Arrays kann ich nicht einfach die [][] alle
weglassen
Ich will ja aufs Richtige zugreifen, menu und da z.B. Zeile oder Spalte
> In meinem abgewandelten Code ist nirgendwo ein> "&" oder ein Cast!
ich weiss das es möglich *(var+s+(z * s_laenge))= ist aber in meinem
Verständnis tue ich mich leichter bei mehrdimensionalen Array bei
&var[][] für die Adresse oder bei var[][]= zu bleiben
> Joachim B. schrieb:>> nutze ich, aber weil ich nicht jedesmal händich das Editorfenster>> anfassen will an verschiedenen Compis, sitzt du immer vor demselben>> Compi mit 32" Monitor?>> Was ist ein "Compi"? Ein Compiler? Seit wann haben Compiler Monitore?> Tippst du den Code vom einem Computer fehlerhaft an den anderen Computer> ab? Warum kopierst du ihn nicht per USB-Stick, Netzwerk, Dropbox, ...
Computer
> Wenn du schon im Forum die Experten fragst, kannst du auch den Rat> annehmen...
och mache ich schon, nur echte Experten sind selten
wie gesagt, dein Text:
> Wenn das ein C Compiler ist, glaube ich das nicht. Der Fehler liegt> woanders. Wenn es C++ ist (z.B. Arduino), dann muss da noch ein Cast> hin:
die Realität:
nee genau anders rum, im Arduino unter #if defined(_AVR_) klappt
char *var_ptr = NULL;
var_ptr = malloc(10);
1
voidsetup(){
2
#if defined (ESP32)
3
#pragma message "ESP32"
4
#elif defined (__AVR__)
5
#pragma message "AVR"
6
#endif
7
8
char*var_ptr=NULL;
9
var_ptr=malloc(10);
10
}
11
12
voidloop(){
13
// put your main code here, to run repeatedly:
14
15
}
16
17
/*
18
ergibt:
19
20
D:\atmel\__ARDUINO__\char_var\char_var.ino: In function 'void setup()':
Joachim B. schrieb:>> Hä? Zeigen. Zeiger kann man beliebig oft übergeben.>> char var[] = {"huhu"};>> void func1(char *);> void func2(char *);>> func1(var); // bis hier kam ich ja im C-Kurs noch mit
1
voidfunc2(char*x){
2
printf("%s",x);
3
}
4
5
voidfunc1(char*param){
6
func2(param);
7
}
8
9
intmain(){
10
func1(var);
11
}
>> Joachim B. schrieb:>>> char *var_ptr = NULL;>>> var_ptr = malloc(10);>>>>>> wird im ESP32 Compiler angemeckert!
Ja, weil malloc() ein void* zurückgibt.
In C++ wird nicht automatisch konvertiert.
1
intmain(){
2
var_ptr=(char*)malloc(10);
3
}
Fertig. Wenn der avr-gcc das akzeptiert und der esp32-gcc nicht, dann
könnte das auch am Aufruf liegen. Man kann den gcc beliebig streng
machen.
>> Was? Die Standard-C-String-Funktionen nutzen>> alle char* bzw. const char*.>> siehst du auch du schreibst bzw. also ODER
Du weißt aber schon, was der Unterschied zwischen "char*" und "const
char*" ist, oder? Und warum man grundsätzlich alle Funktionen "static"
und alle Parameter "const" machen sollte, wenn es möglich ist.
>> Wenn du schon im Forum die Experten fragst, kannst du auch den Rat>> annehmen...>> och mache ich schon, nur echte Experten sind selten
Du ignorierst also gute Ratschläge, weil sie deiner Meinung nach nicht
von einem "echten Experten" stammten? Du kennst den Denkfehler "true
scotsman"?
> unter AVR gehts, unter ESP wird es angemeckert, also genau> entgegengesetzt zu deiner Aussage
Ich habe das Gefühl, dass du keine Ahnung hast, was du eigentlich tust.
Eher nur so rumgemurkse bis es halbwegs tut. Ob der Code gut ist (oder
sich halbwegs gut optimieren lässt), ob er verständlich ist oder nochmal
woanders benutzt werden kann, scheißegal, es funktioniert.
Liege ich mit der Vermutung richtig?
Joachim B. schrieb:> aber dann wenn func1 func2 aufruft> klappt bei mir nie, egal ob mit cast oder nicht
Dann zeig diesen Aufruf doch mal. Du kannst den Parameter direkt so wie
er ist weiter übergeben.
Joachim B. schrieb:> aber wenn func1 func2 aufruft warum klappt das nicht?
Wahrscheinlich ist dein Aufruf falsch.
Joachim B. schrieb:> im Arduino unter #if defined(AVR) klappt
Da gibt's aber ne Warning:
1
warning: invalid conversion from 'void*' to 'char*'
weil es falsch ist. Arduino bügelt die Warnings nur weg. Beim ESP32 wird
es korrekterweise als Fehler gezeigt. Korrekterweise kommt da in C++
(Arduino) immer ein Cast hin.
Joachim B. schrieb:> siehst du auch du schreibst bzw. also ODER
Logisch... z.B. strcpy bekommt einen char* und einen const char* -
ersterer wird überschrieben, zweiterer nicht.
Joachim B. schrieb:> bei mehrdimensionalen Arrays kann ich nicht einfach die [][] alle> weglassen
Das nicht, aber wenn du einen Zeiger auf ein Element eines Unter-Arrays
haben willst, würde ich das letzte [] weglassen und ein "+" nehmen.
Joachim B. schrieb:> unter AVR gehts, unter ESP wird es angemeckert, also genau> entgegengesetzt zu deiner Aussage
Wie gesagt - es wird immer angemeckert, nur die Arduino-IDE stellt den
Compiler auf nachlässig, damit die Anfänger länger nach den Fehlern
suchen müssen. Nur in C ist so etwas erlaubt.
S. R. schrieb:> Du weißt aber schon, was der Unterschied zwischen "char*" und "const> char*" ist
ja so eingermaßen
> Du ignorierst also gute Ratschläge, weil sie deiner Meinung nach nicht> von einem "echten Experten" stammten?
und wie unterscheidet man, man prüft die Aussagen auf Funktion :)
> Ich habe das Gefühl, dass du keine Ahnung hast, was du eigentlich tust.> Eher nur so rumgemurkse bis es halbwegs tut. Ob der Code gut ist (oder> sich halbwegs gut optimieren lässt), ob er verständlich ist oder nochmal> woanders benutzt werden kann, scheißegal, es funktioniert.>> Liege ich mit der Vermutung richtig?
nö absolut falsch
witzigerweise funktioniert mein purer C-Code seit 1990, den ich vom PC
unter DOS über Atari 68k bis heute unter AVR und nun auch ESP32
einsetze.
Nur einige #define oder cast mussten geändert werden aus UBYTE wurde
uint8_t aus ULONG wurde uint16_t
> Ich habe das Gefühl, dass du keine Ahnung hast
da könnte ich nun schmollen denn KEINE Ahnung ist ein starkes Stück.
Alle sind angeblich immer besser, nur hat jeder aber wirklich jeder
Programmierer seine Eigenheiten und Stärken, hier sind viele
Klugschnacker unterwegs, wirklich guten Code gibt es selten, da z.B. in
meinen Augen PeDa Dannegger und Fleury.
Sonst habe ich selten so kompatiblen Code gesehen wie bei den beiden
S. R. schrieb:> Uuund: Wieder hast du eine Abhängigkeit vom Zeichensatz des Quelltextes> zum Zeichensatz des Displays. Wieder nix gelernt, den gleichen Fehler> wieder gemacht. Gratuliere.
Im Anhang aus Spaß mal eine für Arduino erweiterte Variante meines o.g.
Code zum statischen Codieren von Strings. Wenn man diesen Header in
einem Arduino-Sketch inkludiert, kann man so etwas schreiben:
Dieser String wird vom Compiler nach Latin-1 umkodiert und dann als
Latin-1 fix in den Flash gelegt, völlig unabhängig davon, welche
Kodierung die Quelltext-Datei hat. Das serielle Terminal muss dann
natürlich auf Latin-1 gestellt werden. Der String wird nie komplett in
den RAM kodiert, und dann direkt 1:1 ausgegeben, ähnlich als hätte man
geschrieben
1
Serial.print(F("blabla"));
Wobei die Kodierung dann aber von Editor & Compiler abhängig wäre.
Einzelne Zeichen gehen einfacher, weil man kein Array & Flash-Ablage
braucht:
Joachim B. schrieb:>> Du ignorierst also gute Ratschläge, weil sie deiner Meinung nach nicht>> von einem "echten Experten" stammten?>> und wie unterscheidet man, man prüft die Aussagen auf Funktion :)
Dazu muss man aber wissen, wie man das korrekt macht...
Wenn mir mein Autoschrauber erzählt, was an meinem Auto gemacht werden
muss, dann prüfe ich nicht jede Aussage händisch bis ins Detail nach.
Joachim B. schrieb:> witzigerweise funktioniert mein purer C-Code seit 1990, den ich vom PC> unter DOS über Atari 68k bis heute unter AVR und nun auch ESP32> einsetze.
Das finde ich jetzt erstaunlich, denn das bedeutet, dass du es in 30
Jahren nicht geschafft hast, mehr als die absoluten Grundlagen zu
lernen.
Joachim B. schrieb:>> Ich habe das Gefühl, dass du keine Ahnung hast>> da könnte ich nun schmollen denn KEINE Ahnung ist ein starkes Stück.
Zumindest hast du in diesem Thread gezeigt, dass dir massiv
theoretisches Wissen fehlt und du eher wenig Interesse daran hast, es
dir anzueignen.
S. R. schrieb:> Dazu muss man aber wissen, wie man das korrekt macht...
das ist doch nur so ein Klugschnack, ich habe den Code gezeigt der genau
Dr. Sommer seiner Aussage widersprach.
und was kommt von dir?
S. R. schrieb:> Wenn mir mein Autoschrauber erzählt, was an meinem Auto gemacht werden> muss, dann prüfe ich nicht jede Aussage händisch bis ins Detail nach.
eben und ich auch nicht
ich war recht zufrieden mit der newDS1307 LIB
suche seit Tagen den Absturzgrund am ESP32 und habe nun die LIB als
Schuldige entdeckt.
Die adafruit_GFX LIB funktioniert prima am ESP32 und am AVR ABER sie
verballert 600 Byte SRAM mehr (1/3 vom SRAM als ein 328p hat) als die
LCD Basic, die mir aber mit #include avr sofort zeigte das sie am ESP32
nicht mag.
Zurück zur newDS1307 LIB die hat prima auch mit der DS3231 funktioniert,
nur für die Temperatur musste ich eigenen Code schreiben, nutzte das die
Fleury AVR Lib I2C, auch am Arduino.
so nun muss ich mal schauen wo es an der newDS1307 LIB klemmt.
Alle LIB Schreiber haben erst mal meine Hochachtung aber es nervt wenn
JEDER grundlegende Dinge anders macht.
Der Eine will alle µC gleich bedienen ohne Rücksich auf den SRAM
Verbrauch, nur was nutzt ein LIB die sich mal ebn 1/3 vom SRAM mehr
genehmigt als eine schlanke Variante?
Es ist doch doof wenn nur noch die Beispiele funktionieren.
Auch Profiprogger, ja LADYada machen Fehler, da gibt es Beispiele wo
setup am Anfang steht, aber Funktionen aufgerufen werden die am Anfang
noch nicht bekannt sind.
schauen wir uns doch mal 2 Inits an
#include <LCD5110_Basic.h>
LCD5110 myGLCD(8,9,10,11,12);
extern uint8_t SmallFont[];
void setup()
{
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
myGLCD.clrScr();
myGLCD.print("ABCDEFGHIJKLM", CENTER, 16);
}
alles klar mit myGLCD.print(char* text, spalte, zeile) gehts los
aber kein .begin(); dafür .InitLCD();
und dann die Ada
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
void setup()
{
display.begin();
display.setContrast(50);
display.clearDisplay(); // clears the screen and buffer
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0,0);
display.println("Hello, world!");
display.display(); // show
}
klar beides ist möglich, aber woher soll ICH wissen welcher
Programmierstil der Bessere oder Richtige ist?
S. R. schrieb:> Das finde ich jetzt erstaunlich, denn das bedeutet, dass du es in 30> Jahren nicht geschafft hast, mehr als die absoluten Grundlagen zu> lernen.
wo gibt es die?
Ist das nicht von JEDEM Tutor oder Lehrer abhängig
wie man sieht, es gibt keine klare Linie!
erst Recht kein Allheilmittel, nur viel Kritik wenn man es anders macht.
Egal wie "MIES" ich programmiere, als Programmierer wurde ich nie
eingestellt, ich soll Aufgaben bewältigen, dazu gehörte nie PERFEKTER
Code ohne zu wissen was das ist.
Man plagt sich eh schon genug mit Nebenbaustelllen rum, ich will einfach
nur LIBs benutzen ohne mir goße Gedanken zu machen läuft das auf dem
Zielsystem?
Nur echte Spezialisten wissen immer mehr von immer weniger, bis sie
alles von NICHTS wissen.
Joachim B. schrieb:> klar beides ist möglich, aber woher soll ICH wissen welcher> Programmierstil der Bessere oder Richtige ist?
Ob die Funktion jetzt begin oder init heißt ist noch kein
Programmierstil. Das ist ziemlich egal. Eigentlich ist das ziemlich
Arduino spezifisch, und da ist eh alles ziemlich durcheinander.
Normalerweise kommt sowas sowieso in den Konstruktor.
Joachim B. schrieb:> Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
Warum nicht einfach:
1
Adafruit_PCD8544display(7,6,5,4,3);
Joachim B. schrieb:> wo gibt es die?
In Büchern.
Joachim B. schrieb:> Ist das nicht von JEDEM Tutor oder Lehrer abhängig
Das ist kein Argument es nicht zu lernen...
Joachim B. schrieb:> ich will einfach nur LIBs benutzen ohne mir goße Gedanken zu machen> läuft das auf dem Zielsystem?
Mit der Logik lernst du das nie und du plagst dich auf alle Ewigkeit mit
C Grundlagen herum.
Joachim B. schrieb:> Nur echte Spezialisten wissen immer mehr von immer weniger, bis sie> alles von NICHTS wissen.
So ein Blödsinn. Man braucht Spezialisten für spezielle Probleme. Und
viele Spezialisten haben auch eine Menge Ahnung von benachbarten
Gebieten... für vernünftige Beherrschung von C muss man kein Spezialist
sein.
Joachim B. schrieb:> ich habe den Code gezeigt der genau Dr. Sommer seiner Aussage> widersprach.
Nur dass er das eben nicht tut, du hast nur die Warnungen ignoriert...
Joachim B. schrieb:> Alle LIB Schreiber haben erst mal meine Hochachtung aber> es nervt wenn JEDER grundlegende Dinge anders macht.
Was vielleicht daran liegt, dass Arduino keine Vorgaben macht und die
Bibliotheken nicht nur von kompetentem Personal geschrieben werden.
Das machen auch Holzhammerfrickler.
> Der Eine will alle µC gleich bedienen ohne Rücksich auf den SRAM> Verbrauch, nur was nutzt ein LIB die sich mal ebn 1/3 vom SRAM mehr> genehmigt als eine schlanke Variante?
Du meinst also, man sollte keine Bibliotheken anbieten, die für AVR und
ESP32 gleich funktionieren? Oder irre ich da?
> klar beides ist möglich, aber woher soll ICH wissen welcher> Programmierstil der Bessere oder Richtige ist?
Das ist nicht deine Entscheidung.
Du hast dich entschieden, irgendwelche Bibliotheken zu benutzen, also
musst du mit den Entscheidungen derjenigen leben, die die mal
geschrieben haben.
Es steht dir frei, bessere Bibliotheken zu schreiben, aber: Dazu
müsstest du die Grundlagen kennen.
>> Das finde ich jetzt erstaunlich, denn das bedeutet, dass du es in 30>> Jahren nicht geschafft hast, mehr als die absoluten Grundlagen zu>> lernen.>> wo gibt es die?
In Büchern und in der Dokumentation.
> Ist das nicht von JEDEM Tutor oder Lehrer abhängig
Es ist bezeichnend, dass du Fachwissen als "vom Lehrer oder Tutorial"
abhängig machst.
Im Übrigen gibt es einen Unterschied zwischen "Grundlagen der Sprache"
und "effiziente Anwendung der Sprache". Ersteres ist notwendig, aber
nicht hinreichend - wer an den Grundlagen scheitert, wird es nie
ordentlich hinkriegen.
> wie man sieht, es gibt keine klare Linie!
Nein, aber du schließt von "niemand ist perfekt" auf "alle sind
unfähig". Auch, wenn sich nicht alle daran halten - auch nicht alle
Experten - gibt es einen Grundkonsenz an Dingen, die man machen oder
lassen sollte.
> Man plagt sich eh schon genug mit Nebenbaustelllen rum,> ich will einfach nur LIBs benutzen ohne mir goße Gedanken> zu machen läuft das auf dem Zielsystem?
Ja, das merkt man. Bloß nichts verstehen müssen. Bloß nichts lernen.
Dr. Sommer schrieb:> Joachim B. schrieb:>> ich habe den Code gezeigt der genau Dr. Sommer seiner Aussage>> widersprach.>> Nur dass er das eben nicht tut, du hast nur die Warnungen ignoriert.
ach egal, es gibt eine Lösung, einige gehen anders an die Dinge als ich,
ist auch OK.
S. R. schrieb:> Ja, das merkt man. Bloß nichts verstehen müssen. Bloß nichts lernen.
nicht OK scheint mir andere niederzumachen um sich selbst zu erhöhen,
ist das nicht ärmlich?
Ich lese das hier öfter und gestehe das es mir auch mal passiert, aber
deswegen ist es nicht gut.
Ich bin schon wieder weiter und finde meine Lösung ohne in den
Compileroptionen rumzuändern.
Manche Voreinstellung ist ja nicht immer sinnlos, ein absolut perfekt
eingestellter Compiler kann nur noch nerven ohne was am Ergebnis
zwingend zu verbessern, er erreicht nur eines das man nie fertig wird
oder die Lust verliert.
Kleine Bugs oder Unzulänglichkeiten findet man überall es regt mich auf
wenn ich dafür bezahlen musste und sogar noch den Schaden habe, aber
wenn meine kleine DHT22 Anzeige abschmiert merke ich das suche den
Fehler und behebe ihn wenns nervt, ist kein Beinbruch.
Wenn mich aber Pakete nicht erreichen weil das Internet Webformular
Adressfenster 4 Zeilen a 40 Zeichen hat, aber auf dem Paketaufkleber nur
3 Zeilen a 20 Zeichen gedruckt werden, DAS regt mich auf.
Das waren also Profiprogrammierer die damit Geld verdienen?
Joachim B. schrieb:>> Ja, das merkt man. Bloß nichts verstehen müssen. Bloß nichts lernen.>> nicht OK scheint mir andere niederzumachen um sich selbst> zu erhöhen, ist das nicht ärmlich?
Du hast alle Antworten, die nicht direkt auf dein Problem passten und
sofortige Lösung versprachen, übergangen.
Dass du nicht willens bist, dich tiefer mit der Materie zu befassen,
hast du selbst gesagt.
S. R. schrieb:> Du hast alle Antworten, die nicht direkt auf dein Problem passten und> sofortige Lösung versprachen, übergangen.
ach ist das so?
du solltest Lotto spielen als Hellseher!
Das rechtfertigt in deinen Augen andere niederzumachen, man bist du
ärmlich!