Casten: ULONG auf char* ?

hallo Leute,

Ich moechte ein paar ULONG’s in eine Binaer-Datei schreiben, so, das jedes gerade 4 Bytes benoetigt. Ich meine, sprintf() ist ein supi Teil, aber für den Zweck ungeeignet.
Mein Versuche in der Art von „ULONG auf einen char* casten“ (in der main() ) waren nicht von Erfolg gekroent.

Frage 1:
Ist eine „union“ mithin die einzige Methode, um die ULONG’s
auf char* umzuwandeln, oder geht das auch anders?
Frage 2:
Der Ausdruck wo ich „nums[2]“ initialisiert habe, sollte im Bitmuster etwas anders aussehen, oder?
So, dass das erste von je acht Bits einen 1 ist die anderen 0, finde ich.

Hier mein Code:

//fwrite.cpp

#include 
#include 

#define DATEI "zahlen.bin"

union Box
 {
 ULONG uli;
 char feld[4];
 };

int schreibe()
 {
 ULONG nums[4] = {
 1,
 123, 
 ( (1\> 24);
 printf("%i, ", (int)uch);
 }
 printf("\n");

 FILE \*fp = 0;
 fp = fopen(DATEI, "wb");
 if (fp==0) {return 1;}

 // Zahlen binaer in den char-Zeiger schreiben
 // ( sprintf() würde bloss eine Zeichenkette erzeugen )
 // ein long sollte 4 Bytes in der DATEI brauchen, nicht bis zu 11...
 Box box;
 for (i=0; i %u\n", box.uli); 
 Sleep(500);
 }

 printf("\n");
 fclose (fp);
 return 0;
 }

void umwandeln(char \*chz)
 {
 printf("%s\n", chz);
 }

void ulongOut(ULONG uli)
 {
 printf("%u\n", uli);
 }

int main()
 { 
 ULONG uli = ( ('f' (uli) );

 printf("/////////////");
 if (schreibe() == 1)
 {
 printf("schreiben klappte nicht.");
 Sleep(2000);
 return -1;
 }

 if (lese() == 1)
 {
 printf("lesen klappte nicht.");
 Sleep(2000);
 return -1;
 }

 system("pause");
 return 0;
 }

PS: ich schreibe eigentlich nur C++, aber für die ofstream-Objekte kriege ich bei WIN32 - Projekten bloss einen Linker-Fehler, außerdem kann die CreateFile() auch keinen ASCII-Text. Ich verwende VC6, WIN2k. Dev-C++ und dotNet 2003 habe ich, auch Code::Blocks, vewende sie aber kaum.

lg
Martin

Hallo Martin

Ich moechte ein paar ULONG’s in eine Binaer-Datei schreiben,
so, das jedes gerade 4 Bytes benoetigt. Ich meine, sprintf()
ist ein supi Teil, aber für den Zweck ungeeignet.
Mein Versuche in der Art von „ULONG auf einen char* casten“
(in der main() ) waren nicht von Erfolg gekroent.

char* ist ein zeigertyp, d.h., alles, was
char * benutzt, erwartet, dass da eine
Adresse steht, welche auf einen Wert zeigt.

Frage 1:
Ist eine „union“ mithin die einzige Methode, um die ULONG’s
auf char* umzuwandeln, oder geht das auch anders?

Um einen Zeiger aus einem Wert zu machen,
braucht man nur die Adresse mit einem
Adressoperator ‚&‘ zu ermitteln. Diese
Adresse ist dann der entsprechende Zeigertyp.

(üblicherweise wissen hauptsächlich
Java-Leute sowas nicht :wink:

Frage 2:
Der Ausdruck wo ich „nums[2]“ initialisiert habe, sollte im
Bitmuster etwas anders aussehen, oder?
So, dass das erste von je acht Bits einen 1 ist die anderen
0, finde ich.

Ich finde, das sieht o.k. aus. Wie sah es
denn genau bei Dir aus?

Hier mein Code:
//fwrite.cpp

Ich hab mal Deinen Quelltext etwas
umgerührt und nur das Wesentliche
herausgezogen.

Vielleicht ist es das, was Du eigentlich
wolltest, vielleicht nicht.

(Ich werd erstmal schlafen gehen)

Grüße

CMБ

#include 
#include 
#include 

#define DATEI "zahlen.bin"

 void bitmuster(ULONG value)
{
 int i, shifter;
 for(i=0,shifter=1; i %u\n", value);
 printf("%%s ==\> %s\n", (char \*)&value);
 printf("%%p ==\> %p\n", &value);
}
 
 void schreibe(char fname[], ULONG value)
{
 FILE \*fp = fopen(fname, "wb");
 assert(fp != 0);

 fwrite( &value, sizeof(value), 1, fp );
 fclose (fp); 
}

 ULONG lese(char fname[])
{
 FILE \*fp = fopen(fname, "rb");
 assert(fp != 0);

 ULONG value=0;
 fread( &value, sizeof(value), 1, fp );
 fclose (fp);
 return value;
}

 int main()
{
 int next\_stack\_value\_1 = 0;
 ULONG vli;
 int next\_stack\_value\_2 = 0;
 ULONG uli = 'f' | ('e'

Hallo Martin,

Ich moechte ein paar ULONG’s in eine Binaer-Datei schreiben,
so, das jedes gerade 4 Bytes benoetigt. Ich meine, sprintf()
ist ein supi Teil, aber für den Zweck ungeeignet.
Mein Versuche in der Art von „ULONG auf einen char* casten“
(in der main() ) waren nicht von Erfolg gekroent.

Frage 1:
Ist eine „union“ mithin die einzige Methode, um die ULONG’s
auf char* umzuwandeln, oder geht das auch anders?

Das mit einen union zu machen ist zudem sehr gefährlich:

  1. Der Code wird auf einer Intel- und einer Motorola-CPU funktionieren, wenn aber die Datei durch die andere CPU erzeugt wurde erhälst du beim Lesen nur noch Schrott (Little/Big Endian).
  2. Es ist nicht garantiert, dass bei jeder Implementierung char 8 und long 32 Bit lang sind !! Zusätzlich muss man noch aufpassen, wie das Allignement geregelt ist.

Also

ULONG uli;
char feld[4];

......
 feld[0] = (char) (uli );
 feld[1] = (char) (uli \>\> 8);
 feld[2] = (char) (uli \>\> 16);
 feld[3] = (char) (uli \>\> 24);

......
 uli = (ULONG) ( (unsigned char) feld[0] );
 uli += (ULONG) (((unsigned char) feld[1]) =xFFFFFF80) und dann in ULONG.

2. "signed char" wird direkt in ULONG gewandelt (0x80 --\> 0x00000080)

Je nach Compiler habe ich schon beide Varianten gesehen.

MfG Peter(TOO)

hallo Leute,

besten Dank an beide, das war nun sehr aufschlußreich!

@Peter(TOO):
dann mache ich besser eine Funktion, die ich bei Bedarf für BigEndian adaptieren kann, oder switche mit einer Konsanten. Aber die Lösung von Semjon kommt wohl eh supi hin. Dem Groessen-Problem sollte man mit

sizeof(ULONG), sizeof(char)

wohl beikommen.

@Semjon: supi, wie elegant Du das machst, danke!
Das Bitmuster haette so aussehen sollen:

00000001-00000001-00000001-00000001

finde ich.

Eines bloss ist mir noch unklar:

 int next\_stack\_value\_1 = 0;
 ULONG vli;
 int next\_stack\_value\_2 = 0;
 ULONG uli = 'f' | ('e'
wozu brauchst Du die "next\_stack\_value\_1"?
Genuegt das nicht:


    ULONG vli = 0;


??

besten Dank für Eure Mühe!
lg
Martin

Hallo Martin

Das Bitmuster haette so aussehen sollen:
00000001-00000001-00000001-00000001
finde ich.

Kommt darauf an, wie rum man es
angezeigt haben möchte. Wenn man
die Funktion bitmuster() etwas
ändert, kann man es seinen Wünschen
anpassen:

 void bitmuster(ULONG value)
{
 bool show\_hibit\_1st = true;
 ULONG shifter = show\_hibit\_1st ? (1\>= 1 : shifter 
d.h., bei "show\_hibit\_1st = true"
wir für "ULONG k = 1" angezeigt:

     00000000000000000000000000000001 (High bits from left)

und bei "show\_hibit\_1st = false" eben
andersrum :wink:



> Eines bloss ist mir noch unklar:  
> 
> int next\_stack\_value\_1 = 0;
> ULONG vli;
> int next\_stack\_value\_2 = 0;
> ULONG uli = 'f' | ('e'
> wozu brauchst Du die "next\_stack\_value\_1"?
> Genuegt das nicht:
>     
>     
> ULONG vli = 0;


Na ja, Du "missbrauchst" da einen 32bit
unsigned int dafür, 4 zeichen in diesem
abzulagern, die Du an anderer Stelle wie 
eine Zeichenkette ausgeben möchtest (char \*).

Eine Zeichenkette ist aber mit '\0' abgeschlossen,
dies wäre das 5,. byte und das passt nicht mehr in 
die 4-byte-Variable. Also guckt man, welche Variable 
"adressmässig" hinter dem ULONG kommt und schreibt 
dort eben die 0 rein :wink:

Da aber in main() der ULONG nicht (mehr)
als char\* angezeigt wird (sondern in einer
Funktion), ist das nun sinnlos, kann raus.

Der gedachte Effekt würde nun erreicht, in
dem man einen 0-Wert im Stack "über" dem
ULONG platziert, dazu müsste man die
Funktion display() wie folgt modifizieren:


     void display(ULONG value)
    {
     int upper\_stack\_value = 0; // '\0' Abschuss der Zeichenkette
     ULONG local\_copy = value; // "getarnte" Zeichenkette: {'F','E','L','D'}
    
     printf("%%u ==\> %u\n", local\_copy);
     printf("%%s ==\> %s\n", (char \*)&local\_copy);
     printf("%%p ==\> %p\n", &local\_copy);
    }


um zu vermeiden, dass bei der Ausgabe
des ULONG als String (char \*) der
String nicht abgeschlossen wird (eben: '\0').

Grüße

CMБ

Hallo Martin,

@Peter(TOO):
dann mache ich besser eine Funktion, die ich bei Bedarf für
BigEndian adaptieren kann, oder switche mit einer Konsanten.

Ich schreibe oft Protokoll-Treiber, welche auf unterschiedlichen CPUs und Compilern funktionieren müssen (PC und MicroController). In der Praxis hat sich gezeigt, dass die „automatische Variante“ besser zu pflegen ist, als die mit der Umschaltung.

Zudem komm3en bei mir die Daten meist sowieso über eine serielle Schnittstelle, sodass ich das Protokoll meist mit einer Statemachine im Interrupt-Treiber implementiere und dadurch die Daten sowieso Byte für Byte verarbeitet werden.

MfG Peter(TOO)

Hallo Semjon,

Besten Dank, alles klar. Ich wollte halt, für Binaer-Dateien, die \0 vermeiden, damit nicht das naechste Byte in der Datei überschrieben wird - beim nachtraeglichen Überschreiben einer Zahl.

Ich mache das mit C++ schon mehr als 4 Jahre, aber ich muss, so scheint es, immer noch einiges dazu lernen, :wink:

Nochmals vielen Dank!
lg
Martin