2016-06-09 37 views
6

Czy jest jakiś sposób sprawdzenia, w jaki sposób struktura C jest pakowana w czasie kompilacji? Czytałem przez kilka podobnych stanowiskach, jak elemencie mogą być pakowane:Zobacz, jak struktury są pakowane w czasie kompilacji

Ale zastanawiam się, czy istnieje jakaś czasie kompilacji wygenerowany plik, który pokazuje mi dokładnie w jaki sposób struktura jest spakowana? Próbowałem sprawdzić plik mapujący wygenerowany przez linker, ale nie ma on tych informacji.

PS: Próbuję uzyskać kilka mikrokontrolerów, aby komunikować się ze sobą poprzez UART i ponieważ jeden jest 16 bitowy, a pozostałe są 32 bitowe, trafiam kilka błędów za każdym razem, gdy aktualizuję te struktury.

+3

Istnieje makro "offsetof()' w 'stddef.h'. Zobacz https://en.wikipedia.org/wiki/Offsetof – cdarke

+0

Informacje o DWARF w każdym obiekcie będą miały to (jeśli włączone są informacje debugowania). Ale wyodrębnienie danych wymaga pewnej analizy. – kaylum

+1

Możesz z pewnością ustawić szerokość 'paczki' dla twojej struktury i wymusić tę samą wartość na obu projektach. – LPs

Odpowiedz

1

Procesor wstępny nie będzie w stanie określić przesunięć struktury, więc żadna ilość samej magii makr nie zrzuci dla ciebie przesunięć.

Jeśli tworzysz wbudowane obiekty docelowe, prawdopodobnie będziesz mógł tworzyć pliki .bin (nie elf, coff, mach-o). Jeśli użyjesz każdego z kompilatorów docelowych do utworzenia tablicy przesunięć w pliku obiektowym, a następnie zrzucisz go do pliku bin, powinno być możliwe porównanie plików bin dla każdego z twoich celów. Dobrym pomysłem byłoby zautomatyzowanie procesu sprawdzania czasu kompilacji.

Oto przykład tego, co mówię:

#include <stdint.h> 
#include <stddef.h> 
typedef struct s1{ 
    uint16_t f1; 
    uint32_t f2; 
    uint64_t f3; 
    int8_t f4[5]; 
    uint32_t f5[2]; 
}s1; 

#define o(f) ((int32_t)offsetof(s1,f)) 

int32_t offsets[]={ 
    o(f1), 
    o(f2), 
    o(f3), 
    o(f4), 
    o(f5) 
}; 

To właśnie tworzy tabelę offsetu. Zbuduj to dla mipsela i x86_64 i porównaj. Oto plik Producent:

T1:=x86_64-linux-gnu 
CC1:=$(T1)-gcc 
OBJCPY1:=$(T1)-objcopy 
T2:=mipsel-linux 
CC2:=$(T2)-gcc 
OBJCPY2:=$(T2)-objcopy 


.PHONY: all cmp clean hexdumps 

all: hexdumps 

hexdumps: hexdump.$(T1).txt hexdump.$(T2).txt 

hexdump.$(T1).txt: offsets.$(T1).bin 
    hexdump -C $< > [email protected] 

hexdump.$(T2).txt: offsets.$(T2).bin 
    hexdump -C $< > [email protected] 

offsets.$(T1).bin: offsets.$(T1).o 
    $(OBJCPY1) -j.data -O binary $< [email protected] 

offsets.$(T2).bin: offsets.$(T2).o 
    $(OBJCPY2) -j .data -O binary $< [email protected] 

offsets.$(T1).o: offsets.c 
    $(CC1) -Wall -c -o [email protected] $< 

offsets.$(T2).o: offsets.c 
    $(CC2) -Wall -c -o [email protected] $< 

clean: 
    -rm -f offsets.$(T1).o offsets.$(T2).o 
    -rm -f offsets.$(T1).bin offsets.$(T2).bin 
    -rm -f hexdump.$(T1).txt hexdump.$(T2).txt 

Teraz porównując przesunięcia jest całkiem proste:

[email protected] ~/se $ cat hexdump.mipsel-linux.txt 
00000000 00 00 00 00 04 00 00 00 08 00 00 00 10 00 00 00 |................| 
00000010 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 
00000020 
[email protected] ~/se $ cat hexdump.x86_64-linux-gnu.txt 
00000000 00 00 00 00 04 00 00 00 08 00 00 00 10 00 00 00 |................| 
00000010 18 00 00 00          |....| 
00000014 

MCI wyemituje odcinek danych 32 bajtów zamiast x86 20 bajtów. Jeśli ustawisz rozmiar offsets, powinieneś być w stanie użyć cmp, aby porównać dwa w swojej kompilacji.

Jeśli cele mają różne wartości końcowe, może zajść potrzeba zmiany makra o, aby użyć ntohl lub niektórych takich, aby oba kompilatory emitowały liczby całkowite w tym samym formacie.