Zugriff auf struct über Pointer unter Visual Studio macht Probleme.

OP #7459914
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?

Angehängte Dateien:
#7459932
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.

#7459992
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)

#7460032
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.

#7460049
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.

#7460067
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
}
OP #7460079
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.

#7460094
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren