2016-08-14 5 views
6

Szukałem już trochę i nie mam na to odpowiedzi.Jakie są dobre wskazówki dotyczące wyboru rozmiaru typów całkowitych?

Kiedy programuję na urządzeniach wbudowanych z ograniczoną pamięcią, ogólnie mam zwyczaj używania najmniejszego typu integralnego/zmiennoprzecinkowego, który wykona zadanie, na przykład, jeśli wiem, że licznik zawsze będzie od zera do 255, zadeklaruję to jako uint8_t.

Jednak w środowiskach o ograniczonej ilości pamięci używam po prostu int do wszystkiego, zgodnie z Google C++ Styleguide. Kiedy patrzę na istniejący kod, często robi się to w ten sposób.

Dla jasności, rozumiem, dlaczego tak się dzieje (Google wyjaśnia to bardzo dobrze), ale nie jestem dokładnie jasny na temat racjonalności tego, co dzieje się w pierwszej kolejności.

Wydaje mi się, że zmniejszenie wielkości pamięci Twojego programu, nawet w systemie, w którym nie zależy Ci na zużyciu pamięci, byłoby dobre dla ogólnej prędkości, ponieważ logicznie, mniej ogólnych danych oznaczałoby więcej jego zmieści się w pamięci podręcznej procesora.

Powikłaniem jest jednak to, że kompilatory automatycznie podają dane i dopasowują je do granic tak, aby można je było pobrać w jednym cyklu magistrali. Sądzę więc, że sprowadza się to do tego, czy kompilatory są wystarczająco inteligentne, aby wziąć, powiedzmy, dwie 32-bitowe liczby całkowite i skleić je razem w jednym bloku 64-bitowym vs. pojedynczo wypełniając każdy z nich do 64 bitów.

Przypuszczam, że sam procesor może to wykorzystać, zależy również od jego wewnętrznych elementów, ale idea, że ​​optymalizacja rozmiaru pamięci poprawia wydajność, szczególnie w przypadku nowszych procesorów, dowodzi fakt, że jądro Linuksa relied for awhile na Opcja gcc -0s dla ogólnego zwiększenia wydajności.

Sądzę więc, że moje pytanie brzmi, dlaczego metoda Google wydaje się być znacznie bardziej rozpowszechniona w rzeczywistym kodzie. Czy brakuje tu ukrytego kosztu?

+0

Wskazówki dotyczące stylu Google nie uwzględniają programowania wbudowanego i pamięci o ograniczonej dostępie. Lub ograniczona pamięć do wytycznych Google ma tylko gigabajt lub dwie z pamięci. Jeśli programujesz 64 KiB lub 1 MB pamięci, pracujesz w zupełnie innym środowisku niż to przyjęte przez Google. –

+1

Należy również wziąć pod uwagę, że pamięć na stosie jest mniej lub bardziej wolna w małych ilościach, a zapisanie pamięci za pomocą wąskiego typu * może * wymagać od kompilatora wydania większej ilości instrukcji. Jest to myślenie za pomocą 'int', chyba że masz powód, aby tego nie robić, np. Gdy jest to element tablicy lub element struct lub class. – EJP

+0

Czasami większy typ danych jest bardziej wydajny. Na przykład 'double' może dać lepszą wydajność, ponieważ nowoczesne procesory są często zbudowane tak, aby natywnie działały na' double's zamiast 'float's (ale jeśli masz ich tonę, to może' float' będzie lepszy, ponieważ może buforować więcej z nich ...). Również '-Os' optymalizuje liczbę instrukcji, które mają być mniejsze, a nie rozmiar obsługiwanych typów danych; ta flaga jest ortogonalna do twojego pytania. – Cornstalks

Odpowiedz

2

Zwykle powód, dla którego powszechnie stosowana jest "metoda google", jest często dość dobry, ponieważ zazwyczaj jest to pierwsza opcja nauczana w materiale dla początkujących. Wymaga to również większego wysiłku (godziny pracy, itp.) W celu optymalizacji nietrywialnego kodu "ograniczonej pamięci" - wysiłku, który jest bezcelowy, jeśli nie jest faktycznie potrzebny.

Jeśli "rzeczywisty kod" jest napisany dla możliwości przenoszenia, to dobrym wyborem domyślnym jest int.

Bez względu na to, czy są napisane do przenoszenia, wiele programów jest zawsze uruchamianych na hostach z wystarczającymi zasobami pamięci i typem int, który może reprezentować wymagany zakres wartości. Oznacza to, że nie trzeba martwić się o wykorzystanie pamięci (np. Optymalizując rozmiar zmiennych w oparciu o określony zakres wartości, które muszą obsługiwać), a program po prostu działa.

Programowanie dla "ograniczonej pamięci" jest z pewnością częste, ale nie jest to zazwyczaj powód, dla którego napisano większość kodu. Sporo nowoczesnych systemów wbudowanych ma więcej pamięci i innych zasobów, więc techniki nie zawsze są dla nich potrzebne.

Dużo kodu napisanego dla tak zwanej "ograniczonej pamięci" również tak naprawdę nie musi być. Jest rzeczą, jak programiści uczą się więcej, że znaczna liczba zaczyna się poddawać przedwczesnej optymalizacji - martwiąc się o wydajność lub wykorzystanie pamięci, nawet jeśli nie ma takiej potrzeby, aby to zrobić.Chociaż na pewno istnieje znaczna ilość kodu napisanego dla "ograniczonej pamięci" z powodu rzeczywistej potrzeby, istnieje znacznie więcej takich kodów napisanych z powodu przedwczesnej optymalizacji.

2

„wbudowane urządzenia ... licznik od zera do 255, będę zadeklarować ją jako uint8_t”

, które mogą być szkodliwe. Zwłaszcza w systemach wbudowanych pobieranie 8-bitowe może być wolniejsze. Poza tym licznik jest prawdopodobnie w rejestrze i nie ma korzyści z używania połowy rejestru.

Głównym powodem używania uint8_t jest zestaw ciągły. Może to być tablica, ale także sąsiedni członkowie w class.

Jak już zauważono, -Os nie ma związku - jego zaletą jest to, że przy mniejszym kodzie, magistrala pamięci ma więcej przepustowości dla danych.

0

Z mojego doświadczenia wynika, że ​​90% całego kodu w większym projekcie nie wymaga szczególnej optymalizacji, ponieważ 95% całkowitego zużycia pamięci i całego czasu wykonania jest wydawane w mniej niż 10% kodu, który piszesz. W pozostałej części kodu spróbuj podkreślić prostotę i łatwość konserwacji. W większości przypadków oznacza to, że używa się ints lub size_t jako typów całkowitych. Zwykle nie ma potrzeby optymalizowania rozmiaru zmiennych lokalnych, ale może to mieć sens, jeśli masz dużo instancji typu w dużej tablicy. Pozycja 6 w znakomitej książce C++ standardy kodowania: 101 zasad, wytycznych i najlepszych praktyk (C++ In-Depth) przez Herb Sutter i Andrei Alexandrescu mówi:

"Poprawność, prostota i jasność na pierwszym miejscu."

Co ważniejsze, zrozumieć, gdzie te mniej niż 10% kodu, które naprawdę wymagają optymalizacji. W przeciwnym razie, utrzymuj interfejsy proste i jednolite.

0

Dobra dyskusja! Ale zastanawiam się, dlaczego nikt nie mówi o wielkości rejestru procesora, architekturze magistrali pamięci, architekturze procesora i tak dalej. Mówienie "int jest najlepszy" nie jest wcale ogólne. Jeśli masz małe systemy wbudowane, takie jak 8-bitowy avr, int jest bardzo złym wyborem dla licznika działającego od 0 ... 255.

Używanie int na ARM, gdzie możesz mieć 16-bitowy interfejs może być bardzo zły pomysł, jeśli naprawdę potrzebujesz tylko 16 bitów lub mniej.

Tak jak w przypadku wszystkich optymalizacji: spójrz na kod generowany przez kompilator, zmień, jak długo działania rzeczywiście biorą i poszukaj zużycia pamięci na stercie/stosie, jeśli jest to konieczne. Nie ma sensu przekazywanie niemożliwego do zapamiętania kodu, by zaoszczędzić gdzieś 8 bitów, jeśli twój sprzęt nadal ma MB.

Korzystanie z takich narzędzi, jak valgrind i profilowanie obsługiwane przez obiekt docelowy/kompilator daje o wiele więcej pomysłów, niż wszelkie teoretyczne dyskusje tutaj.

Nie ma ogólnego "najlepszego typu integer"! Zależy to zawsze od architektury procesora, magistrali pamięci, pamięci podręcznych i trochę więcej.