Arbeiten mit Pointern: Windows -> Funktioniert ; Linux (gleicher Code!!) -> Segmentation Fault.. Wo ist der Unters



  • Hallo 🙂

    Ich hab grad ein kleines Problem.. Um genau zu sein hab ich unter Windows eine Klasse geschrieben und wollte diese jetzt unter Linux nutzen.

    Das Problem: Ein und derselbe Code funktioniert unter Windows aber gibt unter Linux eine "Segmentation fault"..

    Hier die relevanten Codezeilen (damit kopiere ich ein Teilbild einer .bmp im Speicher, ich habs hier aber aufs nötigste gekürzt):

    [....]
    
    int newDataSize   = (height)*(width*3+newAdd); // die größe des Teilbilds im Speicher ausrechnen
    BYTE** newBmpData = (BYTE**)new char[newDataSize]; // den Speicher allokieren
    memset(newBmpData, 0x00, newDataSize); // alles auf 0x00 setzen
    
    for(int curLine = 1; curLine <= height; curLine++) // jede Zeile..
            for(int curPix = 1; curPix <= width; curPix++) // ..und jeden Pixel einzeln kopieren, oder in diesem Fall auf 0xff setzen
            {
                    // SEGMENTATION FAULT schon beim 1. Schleifendurchlauf:
                    *((BYTE*)newBmpData + ((height-curLine) * (width *3 +newAdd) + (3* (curPix-1) +0))) = 0xff;  
            }
    
    [....]
    

    Hier die aufschlüsselung der Fehlerhaften Zeile (Wobei ich denke das das nicht von bedeutung ist da ja der gleiche Code unter windows funktioniert!):

    newBmpData + 
    (
         (height-curLine) // ein .bmp wird "auf dem Kopf" gespeichert -> wenn ich zB die 2. pixelreihe von oben anspringen will muss ich in wirklichkeit die 2. von unten anspringen
         * (width*3 + newAdd) // width * 3 weil jedes Pixel 3 Byte breit is, +newAdd weil die Pixelreihen auf ein vielfaches von 4 aufgerundet werden 
         + (3 * (curPix)) // curPix ist der pixel den ich gerade aus der oben referenzierten reihe haben will, 3* weil eben ein pixel 3 byte umfasst
    )
    

    Was ich schon rausgefunden hab bzw was es vll zu wissen gibt:

    • Die klasse wird jedesmal mit dem gleichen Input Bild und den gleichen Funktionsparametern gefüttert!
    • height, curLine, width, newAdd und curPix haben unter Windows und Linux den selben wert
    • newDataSize ist bei beiden OSen gleich groß
    • newBmpData ist nicht NULL, egal ob es mit malloc() oder mit new[] allokiert wird
    • BYTE wird unter Linux so definiert: #define BYTE unsigned char*

    Ich hoffe ihr könnt mir sagen was ich hier überseh 😕

    Schonmal vielen vielen Dank für jede Hilfe!



  • PointerAreEvil schrieb:

    BYTE** newBmpData = (BYTE**)new char[newDataSize]; // den Speicher allokieren
    

    Das sieht verdächtig aus. Warum Doppelpointer? Offenbar willst du doch die Bilddaten ablegen. Sinnvoller scheint mir hier

    BYTE* newBmpData = new BYTE[newDataSize];
    
    • BYTE wird unter Linux so definiert: #define BYTE unsigned char*

    Was heißt "wird definiert"? Von dir oder von irgendeiner Library, die du benutzt? #define zum Typen definieren ist ziemlicher Murks, aber BYTE als Zeiger zu definieren ist schon halb kriminell.

    typedef unsigned char BYTE;
    


  • Vielen Dank für deinen Post!

    Also dass mit dem "#define BYTE unsigned char*" war ein Schreibfehler, ich hatte schon "unsigned char"!

    Hab jetzt mal dein typedef übernommen, danke!

    "BYTE** newBmpData" war weil ich in anderen Bereichen der Klasse, zumindest in früheren versionen mit einem char** gearbeitet hab.
    Hab das jetzt aber komplett auf BYTE* umgeschrieben, der Fehler bleibt aber 😕

    Wie gesagt, selber code läuft unter Windows..
    Gibts da irgend einen Unterschied den ich übersehe??

    Danke schonmal für eure Antworten!



  • Da Du nicht zu wissen scheinst, was Du tust, solltest Du folgende Dinge ganz besonders meiden:
    - C-style Casts
    - reinterpret_cast
    - #define

    Das, was Du machen willst, geht ganz sicher auch ohne solche Hacks.



  • sehe ich auch so krümelkacker

    ausserdem ist nicht 100pro gesagt dass es unter windows klappt. linux könnte vielleicht einfach nur merken dass du auf speicher der dir nicht gehört zugreifst und schmeisst deswegen eine warnung. windows merkt das nicht oder hat dir ZUFÄLLIG diesen speicher auch zugewiesen.

    aber auf jeden fall:

    PointerAreEvil schrieb:

    for(int curLine = 1; curLine <= height; curLine++) {
        for(int curPix = 1; curPix <= width; curPix++)
    

    das sieht schonmal etwas komisch aus, denn arrays beginnen in C/C++ bei 0 und enden bei n-1. ok, so genau hab ich mich da nicht reingedacht, aber du subtrahierst ja die zähler von dem maximalwert, dann wärs wiederum richtig...

    was du machen könntest: du rechnest dir ja im prinzip eine zahl aus und addierst diese zu deinem speicher wert um darauf zu zugreifen
    speicher dir die zahl einfach mal in einer zusätzlichen variable und prüf jeden durchgang ob diese zahl zufällig grösser bzw gleich deiner newDataSize ist
    wenn ja dann hast du deinen fehler inform von ausserhalb der array grenzen geschrieben. und dann musst du das ganze nochmal überdenken...

    EDIT: nicht richtig geguckt 😣
    ist ja schon im ersten durchlauf, wobei das mit der zusätzlichen variable könnte doch klappen da du ja von hinten dran gehst

    EDIT2: 😃 ein schelm wer von hinten versaut interpretiert :DD



  • Ich hab keine Ahnung warum, aber nachdem ich einen BMP Header angepasst hab funktionierts oO
    Der hat aber mit dem Code eigentlich nichts zu tun, wtf? Naja egal 😃

    Dafür hab ich jetzt wo anders ne Segmentation Fault, aber die sollt ich alleine in den Griff bekommen 😃

    @ Skym0sh0 : Das hat schon seine Richtigkeit das ich bei 1 anfange zu zählen, wurde aus kompatibilitätsgründen mit bereits vorhandenem Code gemacht, auf die Einhaltung der Buffergrenzen hab ich auch geachtet! (und auch wenn hier scheinbar einige meinen ich hab gar keine Ahnung von dem was ich tue, würd ich so nicht unterschreiben 😉 )

    newBmpData ist 1056 Bytes groß und das höchste an das geschrieben wird ist newBmpDAta + 1053 (der Unterschied kommt vom aufrunden auf ein vielfaches von 4!)

    Auch wenn ich irgendwie keine Ahnung hab warum das vorher nicht funktioniert hat (und schon an meinen geistigen Fähigkeiten zweifle) bedanke ich mich recht herzlich bei den Leuten die mir hier geholfen haben, ist echt eins der besten Foren das ich kenne!

    Vielen Dank!



  • PointerAreEvil schrieb:

    Ich hab keine Ahnung warum, aber nachdem ich einen BMP Header angepasst hab funktionierts oO
    Der hat aber mit dem Code eigentlich nichts zu tun, wtf? Naja egal 😃

    Typisches undefiniertes Verhalten. Das ist alles andere als egal. Wenn du die Fehler nun ignorierst, wirst du später gehörig auf die Schnauze fallen.

    Und generell kann ich den anderen nur zustimmen. Verzichte auf Low-Level-Frickeleien und benutze die Abstraktionsmechanismen, die C++ bietet. Du brauchst weniger Zeit und Aufwand zur Entwicklung, zudem wird dein Code übersichtlicher, sicherer und nicht selten auch schneller.



  • Nach meiner Erfahrung ist Linux etwas pingeliger, bzw. der gcc/g++ unter linux. Was unter Windows läuft, muss daher nicht auch unter Linux sofort tun.
    Gerade wenn man so abenteuerliches Pointergefrickel macht wie du da...
    ... kannst ja mal den ddd anschmeissen...


Anmelden zum Antworten