Korzystając z avr-gcc jako przykładu, typy int mają szerokość 16 bitów. Wykonywanie operacji na 8-bitowych operandach w C powoduje, że operandy te są konwertowane na 16-bitowe typy int z powodu promocji liczb całkowitych w C. Czy to oznacza, że wszystkie 8-bitowe operacje arytmetyczne na AVR potrwają znacznie dłużej, jeśli są napisane w C niż jeśli napisane w asemblerze z powodu promocji liczby całkowitej C?
microcontroller
avr
c
pr871
źródło
źródło
Odpowiedzi:
Krótko mówiąc:
Zawsze następuje promocja liczb całkowitych do 16 bitów - wymusza to standard C. Ale kompilator może zoptymalizować obliczenia z powrotem do 8 bitów (kompilatory systemów osadzonych są zwykle całkiem dobre w takich optymalizacjach), jeśli można wywnioskować, że znak będzie taki sam, jak byłby, gdyby typ był promowany.
Nie zawsze tak jest! Niejawne zmiany sygnatur spowodowane promocją liczb całkowitych są częstym źródłem błędów w systemach wbudowanych.
Szczegółowe wyjaśnienie można znaleźć tutaj: Reguły promocji typu niejawnego .
źródło
zgodnie z oczekiwaniami fun1 to wszystko ints, podobnie jak 16-bitowa matematyka
Chociaż technicznie niepoprawny, ponieważ jest 16-bitowym dodatkiem wywoływanym przez kod, nawet niezoptymalizowany ten kompilator usunął adc ze względu na rozmiar wyniku.
tak naprawdę nie dziwi mnie promocja, kompilatory nie robiły tego, nie jestem pewien, która wersja sprawiła, że to się zaczęło, natrafiłem na to na początku mojej kariery i pomimo, że kompilatory promowały się nieczynnie (tak jak powyżej), robiłem promocję, mimo że ja kazał mi robić matematykę uchar, nie był zaskoczony.
i ideał, wiem, że to 8 bitów, chcę 8-bitowy wynik, więc po prostu powiedziałem, żeby wykonał 8 bitów przez całą drogę.
Ogólnie rzecz biorąc, lepiej jest dążyć do rozmiaru rejestru, który idealnie jest wielkością (u) int, dla takiego 8-bitowego mcu autorzy kompilatora musieli pójść na kompromis ... Nie należy przyzwyczajać się do używając uchar do matematyki, o której wiesz, że nie potrzebuje więcej niż 8 bitów, tak jak podczas przenoszenia tego kodu lub pisania takiego kodu na procesorze z większymi rejestrami, teraz kompilator musi zacząć maskować i rozszerzać znaki, co niektórzy robią natywnie w niektórych instrukcjach, i inni nie.
zmuszanie 8 bitów kosztuje więcej. Oszukałem trochę / dużo, potrzebowałbym nieco bardziej skomplikowanych przykładów, aby zobaczyć więcej tego w uczciwy sposób.
EDYCJA na podstawie dyskusji na temat komentarzy
bez niespodzianki. Chociaż dlaczego optymalizator zostawił tę dodatkową instrukcję, czy nie możesz użyć ldi na r19? (Znałem odpowiedź, kiedy ją zadałem).
EDYCJA 2
dla avr
aby uniknąć złego nawyku lub nie 8-bitowego porównania
najwyraźniej optymalizacja była włączona zajmuje tylko sekundę, aby wypróbować własny kompilator, aby zobaczyć, jak wypada w porównaniu z moimi danymi wyjściowymi, ale w każdym razie:
I tak, używanie bajtów do zmiennych wielkości bajtów, z pewnością na avr, pic itp., Pozwoli ci zaoszczędzić pamięć i naprawdę chcesz ją zachować ... jeśli tak naprawdę używasz, ale jak pokazano tutaj, jak najmniej będzie w pamięci, jak najwięcej w rejestrach, więc oszczędności flash wynikają z braku dodatkowych zmiennych, oszczędności pamięci RAM mogą, ale nie muszą być rzeczywiste.
źródło
unsigned char
więc musi przeprowadzić promocję do 16 bitów, zgodnie z wymaganiami według normy.(a<<8)|b
jest zawsze niepoprawny dla każdego systemu, w którymint
jest 16 bitów.a
zostanie niejawnie awansowany doint
którego jest podpisany. W przypadkua
przechowywania wartości w MSB, kończysz przesuwanie tych danych do bitu znakowego 16-bitowej liczby, co wywołuje niezdefiniowane zachowanie.Niekoniecznie, ponieważ nowoczesne kompilatory wykonują dobrą pracę w zakresie optymalizacji generowanego kodu. Na przykład, jeśli napiszesz,
z = x + y;
gdzie są wszystkie zmienneunsigned char
, kompilator musi je wypromowaćunsigned int
przed wykonaniem obliczeń. Ponieważ jednak wynik końcowy będzie dokładnie taki sam bez promocji, kompilator wygeneruje kod, który po prostu doda zmienne 8-bitowe.Oczywiście nie zawsze tak jest, na przykład wynik
z = (x + y)/2;
zależy od górnego bajtu, więc nastąpi promocja. Nadal można tego uniknąć bez uciekania się do montażu poprzez rzutowanie wyniku pośredniego z powrotem naunsigned char
.Niektórych takich nieefektywności można uniknąć za pomocą opcji kompilatora. Na przykład wiele 8-bitowych kompilatorów ma opcję pragma lub przełącznik wiersza polecenia, aby zmieścić typy wyliczeń w 1 bajcie, zamiast
int
zgodnie z wymaganiami C.źródło
int
, ponieważchar
najprawdopodobniej nie będzie miał takiej samej rangi konwersji jakint
na żadnej platformie.int
(tak, to niespójne). C11 6.7.2.2Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined...