2013-08-23 10 views
5

Pracuję z osadzonym kompilatorem C (układ ARM cortex-m3) i wydaje się, że inicjuje on niewłaściwą wartość do struktury. Dlaczego to się dzieje? Jeśli jest to problem wyrównania, czy kompilator nie powinien wiedzieć, czy dopasować int32u do granicy 4-bajtowej?Dlaczego kompilator inicjuje tę zmienną na niewłaściwą wartość? Czy to jest problem z wyrównaniem?

Uwaga: printf jedynie wyrzuca bajty z portu szeregowego. W tym układzie nie ma implementacji stdio.h.

typedef struct 
{ 
    int32u startTime; 
    int16u length; 
    int32u offTime; 
} Cycle; 

Cycle cycle = 
{ 
    315618000, 
    1200, 
    0 
}; 


void init() 
{ 
    printf("\r\nInitialized! Cycle Start: %d", cycle.startTime); 

    cycle.startTime = 315618000; 
    cycle.length = 1200; 

    printf(" Cycle Start: %d", cycle.startTime); 

} 

wyjściowa: przygotowanej! Cycle Start: 631237200 Cycle Start: 315618000

Uwaga:: to nie jest kwestia printf. Debugger weryfikuje również wartość w pamięci jako 631237200.

+0

'"% d "' wymaga argumentu 'int'.Prawdopodobnie zadziała, jeśli 'int' będzie 32-bitowe, ale po prostu spróbuj zmienić format z' "% d" 'na' "% lu" 'i jawnie rzucając argument na' unsigned long'. –

+2

Czy twój kompilator dokumentuje 'void main() 'jako poprawną definicję' main'? Czy masz '#include '? –

+1

@KeithThompson: Chociaż całkowicie zgadzam się, że '% d' jest błędne, wątpię, aby chodziło o specyfikatory konwersji (lub nawet o wielkości całkowite), ponieważ wydaje się, że działają one dla drugiego' printf() '. – alk

Odpowiedz

1

W niektórych systemach wbudowanych, inicjalizacji statyczne nie jest skonfigurowany do automatycznego zdarzyć. Jest to sprzeczne ze specyfikacjami C, ale czasami tak właśnie jest. Należy zauważyć, że może to dotyczyć zarówno segmentów danych, jak i bss, tzn. Może się okazać, że niezainicjowana statystyka NIE może być również inicjowana do zera.

Rozwiązanie tego jest, niestety, specyficzne dla systemu. Możesz znaleźć coś w dokumentacji systemu kompilatora, która umożliwia wywołanie inicjalizacji elementów statycznych.

+0

Zwykle oznacza to, że kompilator języka C oczekuje, że jakiś komponent środowiska wykonawczego wyzeruje plik .bss i załaduje prawidłowe (stałe) segmenty danych we właściwym miejscu w pamięci. Brak takiego czasu pracy, musisz napisać sam. (Albo po prostu zawiedliście podczas tworzenia mapy linkera, albo odrzucili sekcje podczas przekształcania pliku binarnego, który ma zostać uruchomiony, np. Podczas kopiowania z elfa do pliku binarnego) – nos

+0

Dla segmentu danych kompilator generuje funkcje inicjalizacyjne do zainicjowania statyka. Te muszą być wywołane w CRT (przed głównym). To może być przydatne. http://gcc.gnu.org/onlinedocs/gccint/Initialization.html – Ziffusion

1

[Edytuj] My sugerowane poniżej tego sizeof (int) == 2 prawdopodobnie nie kwestia jak " Cycle Start: %d", cycle.startTime łatwo wypisuje wartości> 64k. Podejrzewam problem z wyściółką. Ale stosuje się niższe zalecenie dotyczące printf(), nawet jeśli nie wyjaśniają tego problemu.


Inicjalizacja cycle w efekcie robi cycle.startTime = 315618000. Twój int/unsigned rozmiar jest prawdopodobnie 2, dlatego inicjalizacja przepełnia. Zamiast:

Cycle cycle = { 
    315618000LU, 
    1200, 
    0 
    }; 

Twój printf() należy również użyć specyfikatora formatu dopasowanie do uint32_t

#include <inttypes.h> 
printf("Cycle Start: %" PRIu32 "\n", cycle.startTime); 
printf("Length  : %" PRIu16 "\n", cycle.length); 
+1

Czy OP mógłby być tak miły i skomentować tę odpowiedź, ponieważ jestem naprawdę ciekawy, czy dodatek "LU" wykonał zadanie. – alk

+0

@alk I _think_, ponieważ ponieważ przyjęta odpowiedź implikuje statyczną inicjalizację _nie_ się nie wydarzyło, to, co zostało wydrukowane, było tym, co się stało w niezainicjowanym 'cycle.startTime', być może z poprzednich uruchomień. Ach, słabości osadzonego świata. – chux

0

Prawdopodobnie możesz dowiedzieć się, co się dzieje, wyświetlając kod zespołu. Nie wiem, czy twój kompilator to GCC. Jeśli jest to flaga -S, powinna utworzyć plik zespołu nazwany jako plik wejściowy, ale z rozszerzeniem .s.

Dzięki temu powinieneś być w stanie zobaczyć, jakie wartości są przypisane do globalnej zmiennej strukturalnej.

Inną rzeczą, która może być nie tak, jest funkcja printf. Jeśli nie użyłeś prototypu funkcji, który deklaruje to jako funkcję varargs, taką jak int printf(const char *fmt, ...), połączenie zostanie wykonane nieprawidłowo.

Co najmniej jedna architektura, którą znam, wszystkie wpisy vararg mają maksymalne wyrównanie, ponieważ funkcja nie wie, co otrzymuje. Normalne funkcje przekazują wartości na stosie z zadeklarowanym wyrównaniem typów. Jeśli printf nie ma prototypu, język C przyjmie wszystkie argumenty int i spróbuje je przekazać w ten sposób. W międzyczasie sama funkcja printf będzie próbowała pobierać argumenty jako varargs i może z łatwością zrzucić tu i tam kilka bajtów.