2014-04-16 10 views
10

Mam kod, który działa odmiennie od GCC i Atmel studio:C ekspresji oceny inaczej w dwóch różnych kompilatorów

uint32_t tc = 107900; 
int8_t m = 59; 

tc = tc - (m*1800); 

na GCC, wynik w tc 1700, zgodnie z przeznaczeniem.

W AtmelStudio wynik tc wynosi 132772, co nie jest poprawne.

Problem polega na tym, że termin m*1800 jest obliczany z ograniczoną precyzją m przy użyciu AtmelStudio.

Moje pytanie brzmi, który kompilator robi to poprawnie?

Dziękuję.

+4

Wyobrażam sobie, że rzutowanie 'm' na' uint32_t' w wyrażeniu (np. 'Tc = tc - ((uint32_t) m * 1800)') dałoby pożądane wyniki, ale nie jestem pewien, czy jest to wymagane według specyfikacji języka C. –

+1

... lub użyj '(m * 1800L)', ponieważ produkt arytmetyczny 59 * 1800 nie mieści się w _minimum_ C określonym zakresie 'int' od -32767 do +32767, ale pasuje do _minimum_ C określonego' long' zasięg. – chux

+0

Oczywiście ten kompilator domyślnie używa 16-bitowych liczb całkowitych. Oczekiwane zachowanie. –

Odpowiedz

6

Obie robią to poprawnie. Wyrażenie m * 1800 zostanie obliczone jako typ int. Jeśli int ma 32 bity, będzie to 106200. Jeśli int ma 16 bitów, co jest całkowicie dopuszczalnym sposobem implementacji kompilatora języka C, to jest to -24872.

+2

W tym drugim przypadku jest on niezdefiniowany. –

+0

Nie doskonały, tylko standardowy, ale wystarczający dla +1 :-) – peterh

+0

Dzięki, więc ma to związek z domyślnym rozmiarem stałej. – NXT

10

Wygląda na to, że na AtmelStudio int jest 16-bitowy, więc m*1800 przepełnia się, wywołując niezdefiniowane zachowanie. W twoim przypadku zachowanie, jakie kompilator dał, było prawdopodobnie redukcją modulo 65536 w zakresie [-32768,32767], dając -24872. Następnie tc - (m*1800) jest 132772.

Do tego trzeba oddać albo m lub 1800 do uint32_t lub innego typu (np long) uniknąć, gdy wynik nie będzie przepełnienie przed wykonaniem mnożenia.