Forum: PC-Programmierung Zugriff auf struct über Pointer unter Visual Studio macht Probleme.


von B. P. (skorpionx)


Angehängte Dateien:

Lesenswert?

1
typedef struct
2
{
3
    unsigned short BM_Kennung;
4
    unsigned long BMPDateiGroesse;
5
    unsigned long Reserve;
6
    unsigned long OfssetZuDaten;
7
} BMP_DateiKopf_type;
8
-----------------
9
FileLesenStatus = ReadFile(InDateiHandle, PointerBmpDaten,
10
        FileInLaenge, &AnzahlGelesenenByte, 0);
11
-----------------
12
 unsigned long    Offset1, Offset2;  
13
 BMP_DateiKopf_type *Kopf;
14
 Kopf = (BMP_DateiKopf_type*)PointerBmpDaten;
15
 Ofset1=Kopf->OfssetZuDaten;   //Offset1 = 2621440 ud das ist falsch!
16
 Offset2 = *(unsigned long*)((char*)PointerBmpDaten + 10);   //Offset2 = 62  //und das ist richtig
Unter Visual Studio C++/CLI lese ich ein .BMP File in Speicher.
Danach setze ich Pointer auf struct vom BMP Kopf auf den
PointerBmpDaten. Ein Versuch über den KopfPointer den Inhalt
vom Kopf zu lesen schlägt, fehlt. Eine Kombination z.B. mit
*(PointerBmpDaten + 10 ) gibt den richtigen Wert.
Das Programm lief unter C++ Builder ohne solche Problemen.
Hat jemand einen Rat?

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

B. P. schrieb:
> BMP_DateiKopf_type *Kopf;

Und wo weist du dem ganzen Speicher zu? Das ist erstmal nur ein Pointer 
der ins Nirva zeigt.

von Harald K. (kirnbichler)


Lesenswert?

Irgend W. schrieb:
> Und wo weist du dem ganzen Speicher zu?

Das passiert in Zeile 14.

> Das ist erstmal nur ein Pointer der ins Nirva zeigt.

Nö.

Das Problem ist vermutlich eine falsche Annahme über die Größe der 
Struktur BMP_DateiKopf_type.

Stichworte Alignment, packed struct.

von Peter (pittyj)


Lesenswert?

Da wird wohl
  unsigned short BM_Kennung;
intern von 16 auf 32 Bit erweitert, damit die weiteren 32 Bit Zugriffe 
aligned sind.

Mit diversen Optionen kann man den Compilern das erlauben oder 
verbieten.
Portabel ist das nicht, einfach eine Struct über einen Speicherbereich 
zu legen.

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Harald K. schrieb:
> Irgend W. schrieb:
>> Und wo weist du dem ganzen Speicher zu?
>
> Das passiert in Zeile 14.

jo, sorry übersehen. Dann wäre aber auch mal das ganze fehlende 
Drumherum interessant?

von B. P. (skorpionx)


Lesenswert?

Harald K. schrieb:
> Das Problem ist vermutlich eine falsche Annahme über die Größe der
> Struktur BMP_DateiKopf_type.
1
SizeStructurKopf = sizeof(BMP_DateiKopf_type);
SizeStructurKopf == 16. Aber im File sind das 14 Byte...
Also das ist die Ursache. Wie kann man das umgehen...?

von J. S. (jojos)


Lesenswert?

https://learn.microsoft.com/de-de/cpp/preprocessor/pack?view=msvc-170

aber mit push/pop verwenden, sonst verstellt man das für den ganzen 
folgenden Code

von Harald K. (kirnbichler)


Lesenswert?

J. S. schrieb:
> https://learn.microsoft.com/de-de/cpp/preprocessor/pack?view=msvc-170

Das bezieht sich auf den C++-Compiler. Hier wird aber kein C++ 
verwendet, sondern "C++/CLI". Und das scheint #pragma pack nicht zu 
kennen:

https://stackoverflow.com/questions/5029838/c-cli-struct-class-alignment

(Wie schon im anderen Thread zum Thema angemerkt: C++/CLI ist nicht 
C++, sondern eine andere Programmiersprache)

von J. S. (jojos)


Lesenswert?

also bei mir funktioniert es
1
#include "pch.h"
2
#include <cstdio>
3
4
using namespace System;
5
6
typedef struct
7
{
8
    unsigned short BM_Kennung;
9
    unsigned long BMPDateiGroesse;
10
    unsigned long Reserve;
11
    unsigned long OfssetZuDaten;
12
} BMP_DateiKopf_type;
13
14
#pragma pack(push, 2)
15
typedef struct
16
{
17
    unsigned short BM_Kennung;
18
    unsigned long BMPDateiGroesse;
19
    unsigned long Reserve;
20
    unsigned long OfssetZuDaten;
21
} BMP_DateiKopf_p_type;
22
#pragma pack(pop)
23
24
int main(array<System::String ^> ^args)
25
{
26
    printf("sizeof unpacked: %d\n", sizeof(BMP_DateiKopf_type));    //sizeof packed: 16
27
28
    printf("sizeof packed: %d\n", sizeof(BMP_DateiKopf_p_type));    // sizeof packed: 14
29
30
    Boolean b;
31
32
    return 0;
33
}

übersetzen mit cl /clr für die CLI Unterstützung.

von Roger S. (edge)


Lesenswert?

Harald K. schrieb:
> Das bezieht sich auf den C++-Compiler. Hier wird aber kein C++
> verwendet, sondern "C++/CLI". Und das scheint #pragma pack nicht zu
> kennen:

das kennt das sehr wohl, appliziert es aber nur auf 'native' types.
ref struct/class wie im verlinktem Stackoverflow Artikel funktionieren 
damit nicht. Managed Types nutzen .NET Attribute fuer das packing.

> (Wie schon im anderen Thread zum Thema angemerkt: C++/CLI ist *nicht*
> C++, sondern eine andere Programmiersprache)

Der C++ Teil von C++/CLI ist das Standard (Microsoft) C++ und wird auch 
vom selben Compiler uebersetzt.

von Harald K. (kirnbichler)


Lesenswert?

Roger S. schrieb:
> Der C++ Teil von C++/CLI ist das Standard (Microsoft) C++

Wo trennst Du das? Schon das da
1
int main(array<System::String ^> ^args)
2
{
3
    printf("sizeof unpacked: %d\n", sizeof(BMP_DateiKopf_type));    //sizeof packed: 16
4
    printf("sizeof packed: %d\n", sizeof(BMP_DateiKopf_p_type));    // sizeof packed: 14
5
    Boolean b;
6
    return 0;
7
}

ist kein C++.

von Roger S. (edge)


Lesenswert?

Harald K. schrieb:
> Roger S. schrieb:
>> Der C++ Teil von C++/CLI ist das Standard (Microsoft) C++
>
> Wo trennst Du das? Schon das da

Das hier wird (auch in derselben translation unit) in nativen code 
uebersetzt, der Maschinencode ist derselbe wie wenn der compiler das im 
C++
only mode machen wuerde:
1
int puresC()
2
{
3
    printf("sizeof unpacked: %d\n", sizeof(BMP_DateiKopf_type)); //sizeof packed: 16
4
    printf("sizeof packed: %d\n", sizeof(BMP_DateiKopf_p_type));    //sizeof packed: 14
5
     return 0;
6
}

Das hier ist eine .NET funktion, der Aufruf der native funktion wird als 
IL code erzeugt und landet im .NET assembly teil.
1
int main(array<System::String ^> ^args)
2
{
3
    return puresC();
4
}

von B. P. (skorpionx)


Lesenswert?

J. S. schrieb:
> also bei mir funktioniert es
1
#pragma pack(push, 2)
2
typedef struct
3
{   unsigned short BM_Kennung;
4
    unsigned long BMPDateiGroesse;
5
    unsigned long Reserve;
6
    unsigned long OfssetZuDaten;
7
} BMP_DateiKopf_type;
8
#pragma pack(pop)
9
typedef struct
10
{    unsigned long   InfoBlockGroesse;
11
    long   BitmapBreiteInPixel;
12
    long   BitmapHoeheInPixel;
13
    unsigned short  FarbEbenebAnzahl;
14
    unsigned short  BitsProPixel;
15
    unsigned long   CompressionInfo;
16
    unsigned long   BildDatenGroesseInBytes;
17
    unsigned long   X_AufloesungPixelProMeter;
18
    unsigned long   Y_AufloesungPixelProMeter;
19
    unsigned long   AnzahlFarbTabellenEintraege;
20
    unsigned long   AnzahlFarben;
21
}BitMapInfoHeader_type;
Nach dieser Änderung fuktioniert das auch bei mir. Das ist
wichtig weill nächste typedef struct definiert BitMapInfoHeader_type.

von B. P. (skorpionx)


Lesenswert?

Was macht dieses Block:
#pragma pack(push, 2) bis #pragma pack(pop).
Gilt das nur in diesem Block Bereich?

von Falk S. (falk_s831)


Lesenswert?

B. P. schrieb:
> Was macht dieses Block:
> #pragma pack(push, 2) bis #pragma pack(pop).
> Gilt das nur in diesem Block Bereich?

Jep, das ist dazu da, das Padding einer struct auf die Maschinenbreite 
anzupassen. Das push und pop überschreibt nur für den beinhalteten 
Bereich die Einstellungen für dieses struct-Alignment. Daher auch keine 
#includes in so einem Bereich dazwischen machen, es sei denn, du weißt, 
was du tust.

Ansonsten sollte eigentlich eine BITMAPINFOHEADER-struct bzw. BITMAPINFO 
aus den nativen Windows-Types exakt das selbe tun, was du hier manuell 
deklariert hast. Edit: sorry, BITMAPFILEHEADER.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.