www.mikrocontroller.net

Forum: Compiler & IDEs Warnungen vermeiden


Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

man möchte ja nach Möglichkeit unnötige Initialisierungen lokaler
Variablen vermeiden. Wenn ich aber nur dort initialisiere, wo es nach
der Logik des Algorithmus nötig ist, bekomme ich vom gcc (der den
Algorithmus natürlich nicht durchschauen kann) die Warnung, die
Variable "may be used uninitialized".

Ich häufe nicht gerne Warnungen an, damit ich neue, ernst zu nehmende
Warnungen leichter entdecke. Daher meine Frage: habe ich eine Chance,
ihm zu sagen, daß er mich (im jeweiligen Fall) nicht warnen muß oder
brauche ich wirklich eine eigentlich überflüssige Initialisierung?

Dank und Gruß, Philipp.

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zeig doch mal nen Fetzen Code, vielleicht ist die Warnung ja tatsächlich
berechtigt...

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich aber nur dort initialisiere, wo es nach
> der Logik des Algorithmus nötig ist, bekomme ich vom gcc (der den
> Algorithmus natürlich nicht durchschauen kann) die Warnung, die
> Variable "may be used uninitialized".

Normalerweise kommt diese Warnung nur, wenn du wirklich nach Definition
der Variable diese ausliest, ohne sie vorher je beschrieben zu haben.
Kannst du mal zeigen, wie dein Code aussieht?

> Ich häufe nicht gerne Warnungen an, damit ich neue, ernst zu
> nehmende Warnungen leichter entdecke.

Gute Idee.

> Daher meine Frage: habe ich eine Chance, ihm zu sagen, daß er mich
> (im jeweiligen Fall) nicht warnen muß oder brauche ich wirklich
> eine eigentlich überflüssige Initialisierung?

Du kannst auch C99 verwenden. Da brauchst du die Variablen nicht alle
am Anfang zu definieren, sondern kannst dies auch da tun, wo du einen
Wert hast, mit dem du sie initialisieren kannst.

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann (fast) jeden Algorithmus so umformulieren bzw. implementieren,
dass dieses Problem nicht auftritt.

Wenn man eine Stelle im Code hat, wo der Compiler eben nicht erkennen
kann, dass eine Variable vor der ersten Verwendung intialisiert wird,
hat man eine Stelle im Code die "stinkt". ("Code smells",
"Smelling Code").

Das ist eigentlich immer ein Anzeichen dafür, dass an diese Stelle
irgendwann Probleme auftreten können.

Darum: Bitte mal ein konkretes Beispiel. Aber kein künstliches, sondern
konkret aus Deinem Programm. Nur keine Angst oder falsche Scham. Durch
Kritik lernst Du zweimal. Erstens, Kritik zu ertragen, zweitens, aus
Kritik einen Gewinn zu ziehen.

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Bitte mal ein konkretes Beispiel."

Kein Problem, hier ist eins:

http://www.mikrocontroller.net/forum/read-4-49709.html#new

Und das sind dann die Warnungen:

SCHEDULE.C: In function `timeradd':
SCHEDULE.C:39: warning: `ipre' might be used uninitialized in this
function
SCHEDULE.C: In function `timerremove':
SCHEDULE.C:82: warning: `irem' might be used uninitialized in this
function


Peter

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In timeradd() besteht die Möglichkeit, daß die while-Schleife verlassen
wird, ohne daß ein einziges Mal "ipre" ein Wert zugewiesen wird.

Kurz vor Ende der Funktion wird "ipre" aber als Arrayindex verwendet;
und da motzt der Compiler vollkommen zurecht.

In timerremove() sieht das auch nicht besser aus.

Der erste Zugriff auf irem ist ein lesender Zugriff und vorher fand
keine Initialisierung statt.

Auch hier motzt der Compiler vollkommen zurecht.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der formalen Analyse von Programmstrukturen sind Compiler wie GCC den
Programmierern oft überlegen.

Er hat nur dann keine Chance, wenn bestimmte Bedingungen nicht
auftreten können, also beispielsweise eine Variable immer einen
bestimmten Wert hat, aber das nur der Programmierer, nicht aber der
Compiler weiss.

Wenn man meint, solchen Code partout verwenden zu müssen, dann kann man
sicherlich auch mit -Wno-uninitialized leben.

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rufus,

"Auch hier motzt der Compiler vollkommen zurecht."

er motzt an keiner Stelle zu recht.

Es handelt sich da nämlich um sich gegenseitig ausschließende Fälle.
Wenn die Zuweisung nicht erfolgt, dann wird der Ausdruck auch nicht
verwendet.

Es handelt sich um das Erzeugen einer verketteten Liste, wo auch der
Sonderfall behandelt werden muß, daß es das erste Element in der Liste
ist und demzufolge kein Vorgänger existiert.
Daher ist es nutzlos, dem Vorgängerindex einen bestimmten Wert
zuzuweisen.


Ich gestehe es dem Compiler aber zu, daß er das nicht erkennen kann und
deshalb lieber warnt. Er ist sich ja auch seiner Unzulänglichkeit bewußt
und warnt eben nur.


Peter

Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jaja, keine Panik, Beispiel kommt ja schon! Bin doch nicht mehr der
jüngste ... (-;

Ich kürze das mal heftig, sonst kapiert niemand, was da los ist. Dieses
Beispiel ist aus einer Routine, die Text auf ein GLCD schreibt:

while (Zeichen)
 {
  unsigned char Breite = 0;
  const unsigned char *BitmapZeiger;
  switch (Zeichen)
   {
    case FILL_LINE:
      while (x++ < 128)
       {
        DisplayWrite(DisplayRead() & Maske);
       }
      break;
    case SMALL_SPACE:
      BitmapZeiger = CharBismaps + SPACE_OFFSET;
      Breite = 2;
      break;
    case TAB:
// Hier kommt jetzt noch ein Haufen Steuercodes für
// verschiedene Zwecke (invertieren usw.)
    default:
      Offset = pgm_read_byte(CharOffsets + Zeichen - ' );
      Breite = 4 + pgm_read_byte(CharOffsets + Zeichen + 1 - ' ')
            - Offset;
      BitmapZeiger = CharBitmaps + (((unsigned int) (Zeichen - ' '))
            < 2) + Offset;
   }
  while (Breite--)
   {
    if (!Haelfte)
      DisplayWrite((DisplayRead() & Maske) |
           (pgm_read_byte(BitmapZeiger++) >> Zeile));
    else
      DisplayWrite((DisplayRead() & Maske) |
           (pgm_read_byte(BitmapZeiger++) << (8 - Zeile)));
    x++;
   }
  DisplayWrite(DisplayRead() & Maske);
  x++;
  Zeichen = *(++Textzeiger);
 }


(Den Kram mit der "Hälfte" muß man an dieser Stelle nicht verstehen;
das brauche ich, wenn die Textzeile zwischen zwei Displayzeilen geteilt
wird.)

Entscheidend ist: ich gehe den String entlang und je nach Inhalt
(Steuerzeichen oder druckbar) muß ich anders reagieren im switch. Wenn
ich nachher die Bitmap eines Zeichens drucken will, setzte ich den
Bitmapzeiger auf die entsprechende Stelle und ermittle die Breite. Wenn
die Breite null bleibt, wird der Bitmapzeiger also gar nicht benutzt.
gcc merkt das natürlich nicht.

Wenn jetzt jemand mit Fehlervermeidung kommt: wenn ich versehentlich
eine Breite setze, wo keine hingehörte, würde auch Quatsch
herauskommen, wenn ich den Bitmapzeiger vorher initialisiere (und keine
Warnung bekomme). Nützt also gar nichts.

Und das ist nur ein Beispiel von vielen. Andere sind z.B. wenn ich in
einer Protokollabarbeitung einen switch für den Zustand im Protokoll
habe. In einen bestimmten Zustand komme ich nur rein, wenn ich vorher
einen Wert aus dem Protokoll entnehmen konnte. Also muß ich das nicht
initialisieren. gcc hat keine Chance. Fehler passieren bei so etwas
nicht.


So gerne ich mich belehren lasse, daß man die Aufgaben auch anders
lösen und den Code so entstinken kann: der Code funktioniert seit
Jahren und wird ohne Komplikationen erweitert. Ich fange nicht an, das
neu zu machen. Vielleicht beim nächsten Mal.

Hier will ich wirklich nur die Warnungen loswerden und hätte mir
vorstellen können, daß es da eine Lösung gibt, denn zumindest mir
begegnet die Situation immer wieder.


Danke einstweilen für alle Antworten!

Autor: Olaf Stieleke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist an einem

const unsigned char *BitmapZeiger = NULL;

denn soviel mehr Arbeit ?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter:

Kannst Du mir das von Dir gesagte (mit dem gegenseitigen Ausschluss)
mal anhand Deiner Funktion timerremove zeigen?

Ich zitiere die hier mal (nur der Formatierung halber sind Kommentare
entfernt)

bit timerremove( funcp func ){
  uchar ipre;
  uchar irem;
  uchar ifol = t_first;
  t_ctrl_struct t_data *p;

  do{
    if( ifol == T_LAST )
      return 1;
    ipre = irem;
    irem = ifol;
    p = &t_ctrl_lst[irem];
    ifol = p->next;
  }while( p->func != func );

  p->next = T_FREE;
  if( irem == t_first ){
    t_first = ifol;
    t_delay += t_ctrl_lst[ifol].delta;
  }else{
    t_ctrl_lst[ipre].next = ifol;
    if( ifol != T_LAST )
      t_ctrl_lst[ifol].delta += p->delta;
  }
  return 0;
}


Hier genügt es, sich die ersten Zeilen der do..while-Schleife
anzusehen. Entweder wird die Funktion hier mit 'nem return beendet,
oder aber ein Lesezugriff auf irem durchgeführt.

Da eine do..while-Schleife mindestens einmal durchlaufen wird ("post
check loop"), sehe ich hier nicht, wie da der Lesezugriff auf die
nicht intialisierte Variable 'irem' umgangen werden kann.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hier genügt es, sich die ersten Zeilen der do..while-Schleife
> anzusehen. Entweder wird die Funktion hier mit 'nem return beendet,
> oder aber ein Lesezugriff auf irem durchgeführt.

Der daraus gelesene Wert (in ipre) wird in diesem Falle allerdings
nicht weiter benutzt.

Die Warnung ist natürlich trotzdem korrekt, es ist für den Compiler
keineswegs sofort ersichtlich, dass diese Benutzung eines nicht
initialisierten Wertes in der Tat harmlos ist.

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Rufus,

ich hab mal alles unwesentliche durch ... ersetzt:
bit timerremove( funcp func ){
  uchar ipre;
  uchar irem;
  uchar ifol = t_first;

  do{
    ...
    ipre = irem;                        // Erstlauf: ipre unbestimmt
    irem = ifol;                        // Erstlauf: irem = t_first
    ...
  }while(...);

  if( irem == t_first ){                // immer true nach Erstlauf
    t_first = ifol;                     // ipre nicht benutzt
    t_delay += t_ctrl_lst[ifol].delta;  // ipre nicht benutzt
  }else{                                // nie true nach Erstlauf
    t_ctrl_lst[ipre].next = ifol;       // ipre benutzt
    ...
  }
}

d.h. wird die Schleife nur einmal durchlaufen (das muß sie ja
mindestens), dann ist irem == t_first und damit wird der else Zweig, wo
ipre verwendet wird, nicht ausgeführt.


@A.K.

"In der formalen Analyse von Programmstrukturen sind Compiler wie GCC
den Programmierern oft überlegen."

Nun in diesem Fall ist es aber der Mensch.
Erwarten tue ich es nicht, aber erstaunen würde es mich auch nicht,
wenn ein Compiler sowas erkennen könnte.


Aber solche Sachen, daß ich für Parameterübergaben nur bestimmte Werte
erwarte, würde ich nie machen.
Mich wundert es immer wieder, wenn Programme abstürzen, weil über die
UART oder Tastatur unerwartete Werte reinkommen. Ist das nur Leichtsinn
oder pure Faulheit ?


Peter

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Prinzip ist das genau das gleiche, wie bei Philip:

Eine Variable wird zu Anfang so gesetzt, daß die Bedingung zum
Verwenden einer anderen uninitialisierten Variablen nicht erfüllt ist.

Und erst wenn die andere Variable auf einen Wert gesetzt wurde, wird
die Bedingungsvariable so gesetzt, daß nun eine Verwendung erfolgt.

Ein Mensch kann derartige logische Verknüpfungen nachvollziehen.


Ich muß z.B. nicht wissen, wieviel Benzin im Tank ist, wenn ich das
Auto stehen lassen will.


Peter

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg Wunsch:

> Der daraus gelesene Wert (in ipre) wird in diesem Falle allerdings
> nicht weiter benutzt.

Das ist eben aus dem Code so nicht direkt ersichtlich. Dieser Code ist
typisch schlechter Stil.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Der daraus gelesene Wert (in ipre) wird in diesem Falle allerdings
> nicht weiter benutzt.
>
> Die Warnung ist natürlich trotzdem korrekt, es ist für den
> Compiler keineswegs sofort ersichtlich, dass diese Benutzung eines
> nicht initialisierten Wertes in der Tat harmlos ist.

Wenn man streng nach C-Norm vorgeht, nicht. Das Verhalten ist
undefiniert, wenn man die Variable liest, ohne vorher was
reingeschrieben zu haben, und zwar auch dann, wenn man den Wert nur in
eine andere Variable kopiert und sonst nie was damit macht. Also ist
der Code eigentlich fehlerhaft.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das Verhalten ist
> undefiniert, wenn man die Variable liest, ohne vorher was
> reingeschrieben zu haben, ...

Zitat bitte?

Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@AK (habe das erst gelesen, nachdem ich meine Antwort abgeschickt
hatte):

> In der formalen Analyse von Programmstrukturen sind Compiler wie
> GCC den Programmierern oft überlegen.

Das stellt aber schon erhebliche KI-Anforderungen, das zu analysieren.
Mit sowas soll sich kein Compilerprogrammierer aufhalten, nur um eine
Warnung zu vermeiden.

Ich überblicke es und könnte ihm (frei nach Hammer) sagen "Vertrau mir
-- ich weiß, was ich nicht initialisiere"

> Er hat nur dann keine Chance, wenn bestimmte Bedingungen nicht
> auftreten können, also beispielsweise eine Variable immer einen
> bestimmten Wert hat, aber das nur der Programmierer, nicht aber
> der Compiler weiss.

Es steht alles im Code und ist noch nicht einmal besonders komplex.
Aber er müßte gezielt danach suchen und ein Compiler hat besseres zu
tun!

> Wenn man meint, solchen Code partout verwenden zu müssen, dann
> kann man sicherlich auch mit -Wno-uninitialized leben.

Das betrifft dann aber gleich alle. Es mag aber eines Tages wirklich
eine versehentlich nicht initialisierte Variable geben: da will ich die
Warnung. Deswegen hatte ich auf eine Lösung gehofft, die individuell für
eine Variable ist.


@Olaf:
Natürlich initialisiere ich derzeit die Variablen überflüssigerweise.
Ich möchte es aber vermeiden aus demselben Grund, weshalb man jede
unnötige Initialisierung weglassen sollte.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mit sowas soll sich kein Compilerprogrammierer aufhalten, nur um
> eine Warnung zu vermeiden.

Der Compiler macht eine Codeflussanalyse, anhand derer er entscheidet,
wie groß die tatsächliche Lebensdauer einzelner Variablen sein muss.
Dabei fallen solche Dinge wie die Initialisierungswarnung
,,nebenbei''
ab.  (Daher fallen sie eben auch nicht ab, wenn du mit -O0
compilierst.)

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig.

Und wenn nun der Compiler feststellt, dass da Mist gebaut wurde mit
unintialisierten Variablen, kann er z.B. nicht optimieren.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Unbekannter

> Und wenn nun der Compiler feststellt, dass da Mist gebaut wurde mit
> unintialisierten Variablen, kann er z.B. nicht optimieren.

Er stellt ja keine Mist fest, sonst würde er ja einen Error melden.

Und zum Optimieren muß er nur wissen, wann die Variable das erste mal
gesetzt und das letzte mal gelesen wird.


Peter

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter:

> Und zum Optimieren muß er nur wissen, wann die Variable das erste
> mal gesetzt und das letzte mal gelesen wird.

Für einen Optimierer ist es noch viel interessanter zu wissen, woher
der Inhalt einer Variablen kommt.

Stichwort: "Register Transfer Analysis" und "Data Path Analysis"

Mit unintialisierten Variablen verhinderst Du solche Analysen und der
Optimierer hat Pech.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Für einen Optimierer ist es noch viel interessanter zu wissen, woher
> der Inhalt einer Variablen kommt.


Warum ?

Das hat doch nur darauf Einfluß, welche Instruktion er nehmen muß (LD,
MOV, IN, LPM).


> Mit unintialisierten Variablen verhinderst Du solche Analysen und
der
> Optimierer hat Pech.

Nun bei allen derartigen Fällen war der Code mit Initialisierung um
gerade dieses überflüssige LDI länger. Also schadet es der Optimierung
in keinster Weise.


Peter

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Das Verhalten ist undefiniert, wenn man die Variable liest, ohne
>> vorher was reingeschrieben zu haben, ...
>
> Zitat bitte?

Ok, stimmt wohl nicht, da es sich um einen unsigned char handelt. Für
allen nicht-char-Typen gilt aber, was ich sagte.

Hier das gewünschte Zitat aus ISO/IEC 9899:1999:

=====================================================

6.2.6.1:

5 Certain object representations need not represent a value of the
object type. If the stored value of an object has such a representation
and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a
representation is produced by a side effect that modifies all or any
part of the object by an lvalue expression that does not have character
type, the behavior is undefined.41) Such a representation is called a
trap representation.

41) Thus, an automatic variable can be initialized to a trap
representation without causing undefined behavior, but the value of
the variable cannot be used until a proper value is stored in it.

=====================================================

Das bedeutet, daß der zufällig in der uninitialisierten Variable
stehende Wert eine "trap representation" sein könnte. Wenn dieser
Wert benutzt ("used") wird -- und das Kopieren in eine andere
Variable zählt bereits als "use" -- ist das Verhalten damit
undefiniert.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, ich hatte es nicht gefunden.

Mir war bislang nicht untergekommen, dass auch nicht-float-Werte
eine trap representation sein können.

Die Ausnahme mit dem character type erscheint natürlich dann
irgendwie unlogisch...  Ich hätte eher erwartet, dass dann diese
Forderung auf alle integer-Typen zutrifft (was ja Sinn hätte).

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter:

> Das hat doch nur darauf Einfluß, welche Instruktion er nehmen muß
> (LD, MOV, IN, LPM).

Um dieses "woher" geht es nicht. Das ist pille-palle. Es geht, wie
ich schon sagte, um die Analyse des Datenpfad. Da setzt der Optimierer
beim umsortieren der Expressions und der Statements an.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Ausnahme mit dem character type erscheint natürlich dann
> irgendwie unlogisch...  Ich hätte eher erwartet, dass dann diese
> Forderung auf alle integer-Typen zutrifft (was ja Sinn hätte).

Das sehe ich auch so.
Alle Integers sind ja vollständig kodiert, d.h. jeder Wert ist gültig.
Um ungültige Integers zu haben, müßte dann ja die Speicherbreite 17
bzw. 33 Bit betragen. Ich hab aber noch nie was von einer 17 oder 33
Bit Architektur gehört.


Peter

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Beispiel für eine Rechnerarchitektur, wo so etwas Probleme bereiten
kann. Nicht mehr ganz taufrisch, aber wer weiss was die Zukunft
bringt:

Der deutsche Grossrechner Telefunken TR440 von '70 hatte zusätzlich zu
seinen 48 Bit Wortbreite noch 2 Bits "Typenkennung". Darin wurde z.B.
zwischen Code und Daten unterschieden. Stand die falsche drin, gab's
beim Zugriff einen Typenkennungsalarm.

Autor: Philipp Sªsse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Um dieses "woher" geht es nicht. Das ist pille-palle. Es geht,
> wie ich schon sagte, um die Analyse des Datenpfad. Da setzt
> der Optimierer beim umsortieren der Expressions und der
> Statements an.

Wenn der Compiler das in diesem Fall tun würde, wäre es ja schön und
gut. Dann würde er auch nicht warnen, sondern im Gegenteil selbst eine
vorhandene Initialisierung weglassen, weil er feststellt, daß sie
überflüssig ist.

Er analysiert es aber nicht und der Code wird größer und langsamer,
wenn man die Initialisierung schreibt, um die Warnung zu vermeiden.
Schließlich blockiert die zu früh gesetzte Variable ja auch Speicher,
wenn der Compiler nicht merkt, daß das nicht nötig wäre.

Und ich bleibe dabei: da ist den Programmierern des Compilers kein
Vorwurf draus zu machen, weil die Analyse solcher Zusammenhänge nicht
einfach nebenbei passiert und die meisten Anwender eine solche
Optimierung wohl ausschalten würden, um den Compiler nicht
auszubremsen.

Da fallen mir wahrlich wichtigere Dinge ein, die man vorher verbessern
könnte! An dieser Stelle würde es ja reichen, wenn der Programmierer
dem Compiler seine eigene Analyse mitteilen könnte. Womit wir wieder
bei meiner Frage wären ... (-;

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.