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 aberWie 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
- #defineDas, 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 gehstEDIT2: 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 egalDafü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 egalTypisches 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...