mikrocontroller.net

Forum: Compiler & IDEs Fragen zu sizeof() in Kombination mit structs


Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich bastle gerade mit Strukturen rum und bin mir ziemlich sicher, 
dass ich hier Fehler mache. Daher wäre für mich und evtl andere 
interessant was man hierbei beachten soll.

Die Größe eines "normal" angelegten Structs kann man ja anscheinend mit
i = sizeof(struct_Benutzer);
bestimmen.

Falls ich aber folgendes mache, mache ich dann etwas falsch?
typedef struct{
uint16_t tagnummer;                             
uint16_t idx; 
} struct_def_Benutzer;

i = sizeof(struct_def_Benutzer);

Außerdem kann ich ja noch folgendes machen:
typedef struct{
uint16_t tagnummer;                             
uint16_t idx; 
} struct_def_Benutzer;

struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
funktioniert das?

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1. Frage: Nein, sizeof kann auf jeden beliebigen Datentyp angewandt
werden.

2. Frage: Ja, und wenn struct_Benutzer ein Zeiger auf die Struktur
ist, kannst du ihn anschließend ähnlich einem Arryay mit 10 Elementen
des Typs struct_def_Benutzer verwenden. So legt man dynamische Arrays
an.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso. Na gut. Ich benutze gerade in meinem Programm solche Arrays etc. 
aber anscheined mache ich etwas grundlegendes falsch. Mein µC stirbt 
leider immer, wenn ich mein Array anlege. Irgendetwas muss mit der Größe 
nicht stimmen. Hmm. Ich forsche weiter und schreibe sicher bald wieder 
was hier rein. :)

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
ist Käse. Besser:
typedef struct BLABLA {...};
struct BLABLA *meine_var = malloc(10 * sizeof(struct BLABLA));

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

Bewertung
0 lesenswert
nicht lesenswert
Sven Pauli wrote:
>
> typedef struct BLABLA {...};
> struct BLABLA *meine_var = malloc(10 * sizeof(struct BLABLA));
> 

Das typedef hat da nichts verloren. Wenn Du den Strukturtyp weiterhin 
als "struct BLABLA" ansprechen willst, hat das typedef keinerlei 
Funktion.

Wenn typedef, dann so:

>
> typedef struct {...} BLABLA;
> BLABLA *meine_var = malloc(10 * sizeof (BLABLA));
> 

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Sven Pauli und  Rufus t. Firefly

Also ich hab mein "struct_Benutzer" vorher schon angelegt. Will darauf 
golbal zugreifen können:
//im H-File
extern struct_def_Benutzer *struct_Benutzer;
//im C-File
struct_def_Benutzer *struct_Benutzer = 0;

Mir ist gerade aufgefallen, dass ich zwar mit
struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
die richtige Größe an Malloc() übergebe, aber ein 
sizeof(struct_Benutzer) nur '2' zurück liefert. Das wird wohl der Fehler 
sein, da ich danach wohl richtig übel einen Überlauf produziere. Aber 
warum stimmt die Größe nicht?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weil struct_Benutzer ein Pointer ist.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso. Dachte sizeof() kapiert das. Also dann erzeuge ich anscheinend 
doch keinen Überlauf. Hab den Fehler immer noch nicht gefunden....

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

Bewertung
0 lesenswert
nicht lesenswert
> Mir ist gerade aufgefallen, dass ich zwar mit
>
> struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));
>
> die richtige Größe an Malloc() übergebe

So und nicht anders wird das gemacht.

> (...) aber ein sizeof(struct_Benutzer) nur '2' zurück
> liefert. Das wird wohl der Fehler sein, da ich danach
> wohl richtig übel einen Überlauf produziere. Aber
> warum stimmt die Größe nicht?

Die Größe stimmt. Nur willst Du ja nicht Speicher für zehn Pointer auf 
eine Struktur anfordern, sondern Speicher für zehn Strukturen.

Also musst Du es so machen, wie eingangs bereits erwähnt.

Du solltest übrigens deutlicher voneinander zu unterscheidende 
Typnamen und Variablennamen verwenden; daß Deine Struktur fast 
genauso heißt wie die Pointervariable ist nicht hilfreich.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mal ein paar Test mit anderen Funktionnen gemacht. Wenn ich 
später in einer anderen Funktion mittels struct_Benutzer[0].Name oder 
ähnlich auf meinen reservierten Speicher zugreifen, bekomme ich bei 
jedem Aufruf der Funktion einen anderen Wert. Es schaut also stark 
danach aus, dass mir der Speicher nicht reserviert wurde. Wenn ich 
jedoch unmittelbar nach dem Anlegen darauf zugreife, dann steht alles 
wunderbar drin.

Man man. Ich würde ja meinen ganzen Code mal posten, aber der ist voll 
mit anderen Sachen und eigentlich auch ganz anders. Das mit 
struct_Benutzer war nur eine Vereinfachung für den Thread hier.

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

Bewertung
0 lesenswert
nicht lesenswert
Josef wrote:

> Es schaut also stark
> danach aus, dass mir der Speicher nicht reserviert wurde.

Nein, es sieht danach aus, dass ihn jemand danach überschrieben hat.
"Reservieren" kannst du ihn nur für weitere malloc(), du kannst aber
keinen Speicherplatz beim Prozessor "reservieren", auf den der dann
nicht mehr schreiben kann...

Wie andere dir schon geschrieben haben, du hast einen ziemlichen
Wirrwar in deinen Bezeichnungen, der es dir (und auch anderen ;-)
mental einfach nicht mehr erlaubt, den Überblick zu behalten.  Solange
du Typnamen vergibst, die zwar einen Zeiger definieren (dessen sizeof
bei deinem Controller offensichtlich 2 ist), die aber so heißen, als
würden sie eine ganze Struktur beinhalten, ist es kein Wunder, dass
da hinterher Speicher überschrieben worden ist, der gar nicht alloziert
worden war.

Wenn du eine Struktur allozieren willst, dann mach dir von mir aus
einen Datentyp für diese Struktur, aber alloziere dann auch die
ganze Struktur.  (Das Ergebnis der Allokation ist dann ein Zeiger
auf die Struktur.)  Wenn du 10 davon allozieren willst, dann
multipliziere das mit 10.

sizeof von einem Zeigertyp zu bilden hat in diesem Zusammenhang keinen
Sinn, sondern deutet nur darauf hin, dass du gar nicht verstanden
hast, was du da gerade tust.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auf den Inhalt eines Structs, der in einem per malloc erzeugten 
Speicherbereich liegt, kann man eigentlich nie mit
struct_Benutzer[0].Name
 zugreifen. Da wird immer ein Pointer mit im Spiel sein.

Mit "ungefähr so" oder "so ähnlich wie" wird das nie was.

Nur so aus Interesse: Für welches Zielsystem programmierst du 
eigentlich?

Oliver

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

Bewertung
0 lesenswert
nicht lesenswert
> Auf den Inhalt eines Structs, der in einem per malloc erzeugten
> Speicherbereich liegt, kann man eigentlich nie mit
>
> struct_Benutzer[0].Name
>
> zugreifen. Da wird immer ein Pointer mit im Spiel sein.

O doch, das geht ganz genau so. Das ist der Array-Pointer-Dualismus.

Vorausgesetzt, die "sinnvoll" benannte Variable struct_Benutzer wird so 
genutzt:
typedef struct
{
// irgendwas
} struct_def_Benutzer;


struct_def_Benutzer *struct_Benutzer;

struct_Benutzer = malloc(10 * sizeof(struct_def_Benutzer));

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Oliver
du schreibst:
Auf den Inhalt eines Structs, der in einem per malloc erzeugten
Speicherbereich liegt, kann man eigentlich nie mit

struct_Benutzer[0].Name

 zugreifen. Da wird immer ein Pointer mit im Spiel sein.
Warum nicht. Das mache ich schon immer so. :) Dachte das sei auch ok so. 
Wie greife ich dann komfortabel darauf zu?
Leider muß ich hier malloc() benutzen weil ich die Größe des "Arrays" 
zur Compilerzeit nicht kenne.
PS: Was passiert eigentlich mit lokalen Arrays, dessen Größe auch zur 
Compilerzeit nicht existieren? Ich reserviere in der Funktion nämlich 
einen Buffer nammens acbuff[Filelength()]. Wobei Filelenght eben erst 
bekannt ist, wenn das Programm läuft und auf eine SD-Karte zugreifen 
kann.
PPS: Ich nutze einen AT90CAN128


@Jörg
Du hast schon recht, dass ich nicht recht weiß was ich tue. Ich versuche 
eben mit dem was ich weiß zu arbeiten. Das ich nicht wußte das sizeof() 
mit dem Pointer nicht zurückgibt was ich mir wünschte, war eben blöd 
angestellt.
Trotzdem finde ich es schon ein bißchen abwertend was da geschrieben 
wurde.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups. Zu spät die Seite aktualisiert.
Danke  Rufus t. Firefly. Dachte schon....

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich weiß echt nicht mehr weiter.
Nachdem ich in meiner Funktion mit malloc mein Array abgespeichert habe 
und diese Funktion (ohne free) wieder verlassen habe, existieren meine 
Werte noch "kurz".
Ich gehe jetzt davon aus, dass mir dieser Speicherbereich "gehört". Und 
da ich ja meine Pointervariable als extern angelegt habe, sollte diese 
doch auch noch existieren.
Wenn ich aber später die Adresse in meinem Pointer anschaue, dann ist 
das garnicht mehr die, die mir malloc() in meiner Unterfunktion 
übergeben hat.

Warum?

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

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich aber später die Adresse in meinem Pointer anschaue, dann ist
> das garnicht mehr die, die mir malloc() in meiner Unterfunktion
> übergeben hat.
>
> Warum?

Weil irgendwas den Pointer überschreibt?

Wie und wo ist denn der Pointer deklariert?

Wie wäre es mit Sourcecode?

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK. Hier mal mein Programm mit all seiner Unschönheit :)
Ich weiß das ist nicht so geschrieben, dass es schnell für jeden 
nachvollziebar ist, aber soll ja auch für mich sein. ;)
//Header
#ifndef _sd_parser_h
#define _sd_parser_h

#include "data_types.h"

//Flags
#define    FTAG  0
#define   FIDX  1
#define    FSUBIDX  2
#define    FANZ  3
#define    FATTR  4
#define    FCOMPL  5




/*return codes:  0 = EXIT_SUCCESS
                1 = FAILURE
                2 = SD Card not present, Data not present.
                3 = Already parsed. Please restart!
                4 = Only std. values loaded?
                5 = Read error
                9 = Malloc() / Speicher Fehler
*/
int app_object_parser(void);

extern can_object_directory_sd_struct *obj_dir_app;

#endif
//C File
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include "sd_parser.h"
#include "object_dir.h"
#include "DOS/dos.h"
#include "DOS/dir.h"
#include "logger.h"


can_object_directory_sd_struct *obj_dir_app = 0;

int state_flag = FTAG;


int app_object_parser(void)
{
  int bsdready = 0;
  int line = 0;
  //SD Initialisierung
  MMC_IO_Init();
  if(GetDriveInformation() != F_ERROR){
    bsdready = 1;
    Fclose();
    Chdir("/");
  }  
  else bsdready = 0;
  
  //obj_dir_app[] erstellen
  uint8_t lines = 0;
  
  if(bsdready==0)
  {
       if(obj_dir_app != 0) free(obj_dir_app);
      obj_dir_app = malloc(sizeof(obj_dir_std)+sizeof(can_object_directory_sd_struct));      //Größe + Terminierung
      rs232_puti(obj_dir_app);
      if(obj_dir_app == 0) return 9;                                       
      int lastline = ((sizeof(obj_dir_std)+sizeof(can_object_directory_sd_struct)+1)  / sizeof(can_object_directory_sd_struct))-1;                            
      obj_dir_app[lastline].tagnummer   = 0;
      obj_dir_app[lastline].idx          = 0x0000;
      obj_dir_app[lastline].Psubidx      = 0x00;
      obj_dir_app[lastline].subidx      = 0;
      obj_dir_app[lastline].attr        = 0x00;
      obj_dir_app[lastline].data_lenght  = 0;
      obj_dir_app[lastline].data        = 0;    
  }
  else if(Fopen("app_par.csv",F_READ)==F_OK)
  {
    unsigned char inbuff[Filelength()];
    if(sizeof(inbuff) != Filelength()){
      return 9;
      }
    if(Fread(inbuff,Filelength()) != Filelength()) return 5;
    int i = 0;
    while((Filelength()-i) != 0)
    {  
      if(inbuff[i] == '\n') lines++;
      i++;
    }
    //leeres obj_dir_app[] erstellen
    if(obj_dir_app != 0) free(obj_dir_app);
    //+x für die Standartwerte+Ende
    obj_dir_app = malloc( (lines+(sizeof(obj_dir_std)/sizeof(can_object_directory_sd_struct))+1) * sizeof(can_object_directory_sd_struct));
    if(obj_dir_app == 0) return 9;
    Fclose();
  }
  else return 5;
  //in obj_dir_app die Standartwerte einfügen
  while( line < (sizeof(obj_dir_std)/sizeof(can_object_directory_sd_struct)) )
  {
    obj_dir_app[line]  = obj_dir_std[line];
    line++;           
  }    
  if(!bsdready) return 4;

  //CSV auf SD-Karte einlesen
  if(Fopen("app_par.csv",F_READ)==F_OK)
  {                  
    int pos = 0;
    int prevpos = 0;
    unsigned char inbuff[10];//Filelength()];
    if(Fread(inbuff,Filelength()) != Filelength()) return 5;
    //Parser
    while(state_flag != FCOMPL)
    {
      while(!(inbuff[pos] == ';' || inbuff[pos] == '\r')) 
        pos++;
      if(state_flag == FTAG)
      {
        int x = pos;
        uint16_t num16buff = 0;
        while((x-prevpos-1)>=0)
        {
          num16buff = num16buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );            //ACHTUNG: double pow(x,y)
          x--;
        }
        obj_dir_app[line].tagnummer = num16buff;  
        state_flag = FIDX;
      }
      
      else if(state_flag == FIDX)
      {
        int x = pos;
        uint16_t num16buff = 0;
        while((x-prevpos-1)>=0)
        {
          num16buff = num16buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
          x--;
        }
        obj_dir_app[line].idx= num16buff;
        state_flag = FSUBIDX;
      }
      
      else if(state_flag == FSUBIDX)
      {
        int x = pos;
        uint8_t num8buff = 0;
        while((x-prevpos-1)>=0)
        {
          num8buff = num8buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
          x--;
        }        
        obj_dir_app[line].Psubidx = num8buff;
        state_flag = FANZ;
      }
      
      else if(state_flag == FANZ)
      {
        int x = pos;
        int num8buff = 0;
        while((x-prevpos-1)>=0)
        {
          num8buff = num8buff + (inbuff[prevpos+pos-x] - 48) * (int)( pow(10,(x-prevpos-1) )+0.5 );    
          x--;
        }
        obj_dir_app[line].subidx=num8buff;
        state_flag = FATTR;
      }
      
      else if(state_flag == FATTR)
      {

        if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_NULL", 14) == 0)
          obj_dir_app[line].attr=0x00;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RO", 12) == 0)
          obj_dir_app[line].attr=0x01;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_WO", 12) == 0)
          obj_dir_app[line].attr=0x02;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RW", 12) == 0)
          obj_dir_app[line].attr=0x03;
        
        //zur nächsten Zeile springen und wieder von Anfang
        //oder Ende der Datei
        if(pos+2 >= Filelength()) state_flag = FCOMPL;
        else 
        {
          state_flag = FTAG;
          line++;
        }
      }
      pos++;
      if(state_flag == FTAG)
        prevpos = pos+1;
      else
        prevpos = pos;
    }    
    Fclose();
    //Listenende markieren
    line++;
    obj_dir_app[line].tagnummer   = 0;
    obj_dir_app[line].idx          = 0x0000;
    obj_dir_app[line].Psubidx      = 0x00;
    obj_dir_app[line].subidx      = 0;
    obj_dir_app[line].attr        = 0x00;
    obj_dir_app[line].data_lenght  = 0;
    obj_dir_app[line].data        = 0;    
    return 0;
  }
  else return 5;  
}

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ahhh. Das Problem lag erstmal hier:
unsigned char inbuff[10];//Filelength()];
hab versehentlich das richtige mal auskommentiert um was zu testen. 
Leider hab ichs nie wieder rückgängig gemacht :(

Jetzt hab ich festegestellt, dass alles läuft bis auf die Pasage mit 
strncmp.
Das die Adresse stand einen Wert zu hoch, also das "+1" weg und schon 
war die Tabelle gut. Leider passiert hier etwas böses:
if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_NULL", 14) == 0)
          obj_dir_app[line].attr=0x00;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RO", 12) == 0)
          obj_dir_app[line].attr=0x01;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_WO", 12) == 0)
          obj_dir_app[line].attr=0x02;
        else if(strncmp((char *)&inbuff[prevpos+1], "DATA_ATTR_RW", 12) == 0)
          obj_dir_app[line].attr=0x03;
Immer wenn ich hier die Funktion strncmp() oder memcmp() benutze, dann 
läuft was über...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.

Wenn inbuff als Array der Länge 10 definiert ist, dann
kann doch der Text DATA_ATTR_NULL gar nicht drinn stehen,
denn das sind ja schon 14 Zeichen (ohne abschliessendes '\0').

Also entweder ist der Text falsch, oder (was wahrscheinlicher ist),
die Arraygröße mit 10 ist viel zu klein.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja. Tut mir leid. Wie oben beschrieben habe ich das mal fälschlich zu 
testzwecken definiert. das muss ein Array der Größe Filelength() sein, 
damit ist dann die ganze Datei in dem Array.
Aber leider funktioniert strncmp und memcmp nicht. Dort stirbt mein 
Programm.  Das es kein echter String ist, weiß ich aber da ich ja 
sowieso nur eine bestimmte Anzahl von Zeichen prüfe, sollte die 
Nullterminierung egal sein, oder?

PS: Wenn ich inbuff[Filelength] definiere, laufe ich dann hier auch 
Gefahr der Speicherfragmentierung?

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PPS: muss natürlich inbuff[Filelength()] heißen

:)

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

Bewertung
0 lesenswert
nicht lesenswert
> PS: Wenn ich inbuff[Filelength()] definiere, laufe ich dann hier auch
> Gefahr der Speicherfragmentierung?

Nein, das ist eine automatische Variable, und die wird auf dem Stack 
angelegt.

Autor: Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber Filelength() (Größe der Datei auf der SD Karte) liefert ja erst zur 
Laufzeit einen Wert... Woher weiß der Compiler dann wie groß die sein 
muß?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Josef wrote:
> Aber Filelength() (Größe der Datei auf der SD Karte) liefert ja erst zur
> Laufzeit einen Wert... Woher weiß der Compiler dann wie groß die sein
> muß?

Gar nicht.

Seit einiger Zeit geht das in C. Man kann Arrays dynamisch zur
Laufzeit in der Größe festlegen.

Wie der Compiler das genau realisiert, kann ich nicht sagen.
Er könnte es durch eine Stackpointer Manipulation zwischendurch
machen, oder er könnte auch auf malloc() ausweichen. Wenn ich
raten müsste, dann würde ich auf letzteres tippen, weil diese
Stackallokierung bei mehreren dynamischen Arrays sonst in ein
Problem ausarten könnte. Der Weg über malloc() ist dann doch
deutlich einfacher: Für das Array wird ein Pointer am Stack
angelegt, für die Allokierung wird ein malloc() gemacht und
in jedem Pfad der zum Verlassen des Arrays führt wird der
korrespondierende free() gemacht.  Ist aber nur eine Vermutung.

Aber eines steht auf jeden Fall fest: Wenn nicht genug Speicher
für das Array vorhanden ist, dann gibts Probleme.

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

Bewertung
0 lesenswert
nicht lesenswert
GCC hat diese Möglichkeit schon sehr lange gehabt in Form der Funktion
alloca().  Die gleiche Mimik wird (und wurde auch schon sehr lange,
ist aber mit C99 erst offiziell geworden) auch für dynamische Arrays
benutzt.

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.