2010-11-30 10 views
0

Angenommen, ich reserviere etwas Speicher.behandelt zugewiesenen Speicher als einen anderen Typ

Ich lege char Werte den ersten 14 Bytes aus einem zuvor definierten Array namens header.

memcpy(buffer, header, 14); 

Dann möchte ich den Rest des zugewiesenen Speicherplatzes als Zeiger auf float behandeln.

float* float_buffer = (float*)(buffer + 14); 
some_function(float_buffer); 

Dann irgendwann später muss ich alle Daten senden.

transmit(buffer); 
my_free(buffer); 

Ist dies der richtige Weg, um Speicher zu behandeln? Ist der Float * in Ordnung? Ich habe Probleme, wo ich Werte verliere und nicht die richtigen Ergebnisse bekomme. Meine Frage ist: Wenn Sie zugewiesenen Speicher als verschiedene Typen behandeln müssen, aber dann senden Sie es als char * am Ende der Verarbeitung ..... ist dies der richtige Weg, es zu tun?

Ich habe die ptr-Werte überprüft und sie sind identisch, wenn sie float * und char * sind, aber ich bekomme nicht das richtige Ergebnis.

Eine meiner Einschränkungen ist, dass ich nur einen Speicherblock zunächst aus einem statischen Puffer reservieren kann. Daher ist es nicht erlaubt, ein anderes malloc als einen anderen Typ (float *) aufzurufen.

+0

Es klingt für mich wie Sie ein Alignment-Problem haben; Können Sie die erwarteten Ergebnisse und die tatsächlichen Fehler anzeigen, die Sie sehen? –

+0

Ja, es war ein Alignment-Problem ... etwas, das mir nicht bewusst war. Ich kann es von hier aus nehmen. Vielen Dank. –

Antwort

3

Um dies zu erreichen (zumindest portabel), müssten Sie (zumindest) sicherstellen, dass float_buffer sizeof (float) -aligned ist. Sie können dies tun, indem Sie sizeof (float) - 1 zusätzliche Bytes zuweisen, das Ergebnis des malloc-Aufrufs modulo sizeof (float) beobachten und die ersten paar Bytes entsprechend ignorieren. (Sie müssen natürlich den ursprünglichen Zeiger beibehalten, um den free() -Aufruf zu tätigen.)

Sie möchten dies wahrscheinlich jedoch nicht tun. Es klingt, als ob der Zweck des 'Puffers' darin besteht, Daten zu sammeln, die über ein Netzwerk oder etwas Ähnliches gesendet werden, und dass die Floats von woanders kopiert werden. Was Sie wirklich tun sollten, ist umgekehrt: Behandeln Sie den Puffer immer als char [], und interpretieren Sie die Quellschwimmer als eine Folge von Zeichen neu, wenn Sie sie kopieren. Das ist

char* buffer = malloc(total_size); 
char* float_start = buffer + header_size; 
memcpy(float_start, (char*)float_source, sizeof(float) * float_count); 
transmit(buffer, total_size); 
free(buffer); 
+0

+1 Gute Lösung zur Vermeidung der Ausrichtung Kopfschmerzen. –

+0

Danke ja es war Ausrichtungsproblem. –

0

ich hier zu spekulieren, aber da der Prototyp für malloc ist

void *malloc(size_t size); 

Sie im Wesentlichen die Puffer vom Typ void * werfen * auf char, so später ein weiteres Stück des Puffers Gießen Float * wäre in Ordnung, solange Sie sich um den Pointer richtig kümmern.

3

Konzeptionell ist das in Ordnung - aber Sie müssen einige zusätzliche Arbeit tun, um sicherzustellen, dass es zuverlässig funktioniert.

Ein potenzielles Problem ist, dass Sie nicht einfach auf eine beliebige Adresse als float zugreifen können. Es kann bestimmte Ausrichtung Anforderungen - die Adresse von malloc() zurückgegeben wird erforderlich, um für den Zugriff als jeder Typ korrekt ausgerichtet, aber sobald Sie 14 an diese Adresse hinzufügen, sind alle Wetten aus (außer für char). Um die korrekte Ausrichtung sicherzustellen, müssen Sie sicherstellen, dass die Adresse, die Sie zu buffer hinzufügen, ein Vielfaches von sizeof(float) ist.

#define PAD_OFFSET(offset, type) ((offset) + sizeof(type) - 1) & ~(sizeof(type) - 1)) 

float *float_buffer = (float *)(buffer + PAD_OFFSET(14, float)); 

Beachten Sie, dass dies eine Lücke schaffen - Polsterung - zwischen dem Zeichen und Ihre Schwimmer: Sie können durch Zugabe von padding anhand der folgenden Formel tun.

Alternativ können Sie eine struct definieren, und der Compiler wird das Padding für Sie herausfinden. Dabei wird ein C99-Funktion ein flexiblen Feldelements genannt:

struct foo { 
    char abc[14]; 
    float xyz[]; 
}; 

struct foo *buffer = malloc(2062); 
memcpy(&buffer->abc, header, 14); 
some_function(&buffer->xyz); 
transmit(buffer); /* Presuming transmit() expects a void * parameter. */ 

Wenn Sie es ohne Polsterung tun möchten, können Sie nicht direkt auf den Speicher als Schwimmer in buffer zugreifen - Sie eine temporäre Array erstellen, müssen und kopiere es in:

float temp[500]; /* Or whatever size */ 
some_function(&temp); 
memcpy(buffer + 14, temp, sizeof temp); 
+0

Danke ja es war Ausrichtungsproblem. –

Verwandte Themen