2009-11-09 20 views
21

Muszę przechowywać instrukcje, polecenia, które będę otrzymywać przez szeregowy. Komendy będą miały długość 8 bitów.8-bitowe wyliczenie, w C

Potrzebuję zachować przezroczystość między nazwą polecenia i jego wartością. Aby uniknąć konieczności tłumaczenia 8-bitowego numeru otrzymanego w postaci szeregowej na dowolny typ.

Chciałbym użyć wyliczeń, aby poradzić sobie z nimi w moim kodzie. Tylko wyliczenie odpowiada na tej platformie 16-bitową liczbę całkowitą.

Platformą jest mikrokontroler AVR ATmega169V, na Butterfly demo board. Jest to system 8-bitowy z ograniczoną obsługą operacji 16-bitowych. To nie jest szybki system i ma około 1 KB pamięci RAM. Nie ma żadnych luksusów, takich jak pliki I/O lub systemy operacyjne.

Więc wszelkie sugestie co do tego, jakiego typu powinienem używać do przechowywania poleceń 8-bitowych?
Musi istnieć coś lepszego niż ogromny nagłówek #defines.

+2

+1 - Dobre pytanie i sensowna optymalizacja. –

+0

Jest to łuk 8-bitowy. –

Odpowiedz

34

gcc „s -fshort-enums może być przydatna:

Przeznaczyć do«enum»typu tylko jako wiele bajtów, ile potrzebuje na deklarowanego zakresu możliwych wartości. W szczególności typem "wyliczenia" będzie równoważny z najmniejszym typem całkowitym, który ma wystarczająco dużo miejsca.

Faktycznie, here to strona z wieloma istotnymi informacjami. Mam nadzieję, że natkniesz się na wiele przełączników GCC, o których istnieniu nie wiedziałeś. ;)

+5

Dodam to do mojej kolekcji użytecznych przełączników gcc, o których istnieniu nigdy nie wiedziałem. –

+4

Ha, zdałem sobie dziś sprawę, że jeśli jestem kompilatorem za pośrednictwem AVR studio 4 IDE, to jest domyślnie włączone –

+0

Chciałbym dodać, że po otrzymaniu polecenia, prawdopodobnie chcesz upewnić się, że przychodząca wartość 8-bitowa jest rzeczywiście poprawną wartością z twojego wylicz, zanim napiszesz i skonwertuj jako swoje wyliczenie. – ndim

3

Nie rozumiem, dlaczego enum nie działał. Porównania i przydziały z enum powinny działać dobrze z domyślnym rozszerzeniem. Tylko uważaj, aby twoje 8-bitowe wartości były poprawnie podpisane (myślę, że chciałbyś mieć niepodpisane rozszerzenie).

Otrzymasz 16-bitowe porównania w ten sposób, mam nadzieję, że nie będzie to problem z wydajnością (nie powinien być, szczególnie, jeśli twój procesor jest 16-bitowy, jak to brzmi).

+0

rzecz w tym, moje wejście szeregowe jest najbardziej niedorzecznie 8bit. Nie jestem pewien, czy ALU działa na 16 czy 8 bitach. Większość pasma montażowego działa tylko na 8-bitowych bajtach, jest ich mniej niż 5, które działają na 2 bajtowe słowa (ADDW, MOVW to wszystko, co mogę przynieść na myśl). Tylko –

+0

Sprawdziłem, to 8bit –

+4

@oxinabox - nadal nie jestem pewien, czy ma to związek z rozmiarem typu wyliczeniowego. Przechowuj wartości 8-bitowe w zmiennej "uint8_t" (lub coś innego, co odpowiada bajtowi). Nadal będziesz w stanie porównać i przypisać im wartości wyliczeniowe (o ile wartości wyliczeniowe są mniejsze niż 256). Po prostu nie używaj typu wyliczeniowego jako typu zmiennego, jeśli dokładny rozmiar jest ważny dla aplikacji –

1

kompilator C Microsoftu pozwala zrobić coś takiego, ale to rozszerzenie (nie jest to standardem w C++ 0x):

enum Foo : unsigned char { 
    blah = 0, 
    blargh = 1 
}; 

Ponieważ oznaczone GCC, nie jestem do końca pewien, czy to samo rzecz jest możliwa, ale GCC może mieć rozszerzenie w trybie gnu99 lub coś podobnego. Zamieszaj to.

+0

Umm, oznaczałem AVR-GCC. Będę musiał sprawdzić, jakie partycje obsługuje. –

+0

Jestem zainteresowany tym, co znajdziesz. To był strzał z jelita. –

+0

Wygląda na to, że MS jest jedynym, który obsługuje taką składnię. –

0

Polecam zatrzymać się na wyliczenia w każdym przypadku z następujących powodów:

  • To rozwiązanie umożliwia mapowanie wartości poleceń bezpośrednio do protokołu szeregowego, co się liczy.
  • Jeśli rzeczywiście używasz 16-bitowej architektury, nie ma tak dużej liczby zalet, aby przejść do typu 8-bitowego. Pomyśl o aspektach innych niż 1 bajt pamięci.
  • W niektórych kompilatorach użyłem rzeczywistego rozmiaru wyliczeniowego przy użyciu minimalnej liczby bitów (wartości, które można dopasować w bajcie używanym tylko bajtem, a następnie 16 bitów, a następnie 32).

Po pierwsze nie należy przejmować się prawdziwą szerokością czcionki. Tylko jeśli naprawdę potrzebujesz efektywnego sposobu przechowywania, powinieneś używać flag kompilatora, takich jak -fshort-enums na kompilatorze GNU, ale nie polecam ich, chyba że naprawdę ich potrzebujesz.

Jako ostatnia opcja możesz zdefiniować "enum" jako dane prezentacji dla poleceń i użyć konwersji do bajtu z 2 prostymi operacjami do przechowywania/przywracania wartości polecenia do/z pamięci (i enkapsulacji w jednym miejscu). A co z tym? Są to bardzo proste operacje, dzięki którym można je wstawiać (ale to pozwala naprawdę używać tylko 1 bajta do przechowywania i z innej strony do wykonywania operacji przy użyciu najbardziej użytecznych elementów zdefiniowanych, zgodnie z potrzebami,

+0

Architektura 8-bitowa. Sprawdziłem sprzęt, to 8bit –

6

Próbujesz rozwiązać problem, który nie istnieje

Twoje pytanie jest oznaczone C. W języku C typy enum w kontekście wartości są w pełni kompatybilne z typami całkowymi i zachowują się tak jak inne typy integralne. Używane w wyrażeniach są poddawane dokładnie takim samym integralne promocje jako inne integralne typy. Gdy weźmiesz to pod uwagę, powinieneś zdać sobie sprawę, że jeśli chcesz przechowywać wartości opisane przez stałe wyliczeniowe w 8-bitowym typie całkowitym, wszystko co musisz zrobić, to wybrać odpowiedni rodzajowy 8-bitowy typ całkowy (na przykład int8_t) i używać go zamiast typu wyliczeniowego. Stracisz absolutnie nic, przechowując stałe wartości wyliczeniowe w obiekcie typu int8_t (w przeciwieństwie do obiektu jawnie zadeklarowanego z typem wyliczenia).

Opisany problem występuje w C++, gdzie typy wyliczeniowe są znacznie od siebie oddzielone od innych typów całkowych. W C++ używanie typu integralnego zamiast typu wyliczeniowego w celu zaoszczędzenia pamięci jest trudniejsze (choć możliwe). Ale nie w C, gdzie nie wymaga żadnego dodatkowego wysiłku.

+2

@ oxinabox.ucc.asn.au: Wątek pojawił się na pierwszej stronie. Nie wiem dlaczego. Rozumiem. * Ty * zredagowałeś to (zastępując "komentarz" słowem "pochwalić", BTW :) a teraz oskarżasz * mnie * o nekromancję terad? – AnT

+0

BTW, odpowiedź była niezła, ponieważ jest najlepszą odpowiedzią. W C enum jest niczym więcej jak deklaracją stałych, przechowywanie wartości jest niezależne od enum. Moje 2 centy. –

+0

Generalnie powinieneś odpowiedzieć na pytanie w swojej odpowiedzi, a nie tylko go krytykować. – whoKnows

0

odpowiedź, która jest istotna dla ARC kompilator (cytat z DesignWare MetaWare C/Przewodnik programista C++ za ARC; sekcji 11.2.9.2)

Rozmiar Wyliczenia Wielkość typu enum zależy od status przełączania * Long_enums *.

■ Jeśli przełączenie * Long_enums * jest wyłączone, typ wyliczania jest mapowany na najmniejszy z jednego, dwóch lub czterech bajtów, tak aby można było reprezentować wszystkie wartości.

■ Jeśli włączono * Long_enums * jest włączone, enum mapuje na cztery bajty (zgodnie z konwencją AT Portable C Compiler AT & T).