Typ wyliczeniowy w języku C ("legitymujący się" jako "enum" 😁) to kolejny ciekawy budulec mogący uprzyjemnić pisanie kodu i sprawić, że podniesie się jego czytelność 📖. Znajduje swoją użyteczność na wielu płaszczyznach i każdy porządny programista powinien tę strukturę znać 💪. Z tego materiału dowiesz się czym jest "enumeracja", jak utworzyć zmienną typu wyliczeniowego oraz jak ją można wykorzystać w praktyce i do jakich celów 🎯!
"ENUM" W JĘZYKU C. TAJNA BROŃ DO DEFINIOWANIA WIELU MOŻLIWOŚCI!
Tytułowy "typ wyliczeniowy" to jest zbiór stałych w postaci liczb całkowitych, opatrzonych własną nazwą. Nadaje się świetnie do sytuacji, w której jest potrzeba zdefiniować wiele ścieżek jakimi może pójść program i jaki wpływ ma mieć każda z nich na dalszy przebieg ℹ️.
Możesz na to patrzeć, jak na menu główne w grze 🎮. Masz przed nosem kilka opcji i musisz wybrać jedną z nich. Zależnie od wyboru, stanie się coś innego 😊. "enum" w języku C działa dokładnie w taki sposób ✅. Jest wiele opcji, natomiast może być zapamiętana tylko jedna możliwość.
Możesz także definiować zmienne typu wyliczeniowego, a następnie przypisać jeden z typów zgodnych z tym typem wyliczeniowym w dowolnym miejscu w kodzie 👍. Oprócz tego, podnosi rewelacyjnie czytelność kodu w połączeniu z instrukcją wielokrotnego wyboru "switch" (więcej szczegółów w odrębnym artykule) 🏆.
"enum" jest skrótem od "enumeration", czyli "enumeracja". A enumeracja to inaczej "wyliczenie". A wyliczenie, to nic innego jak lista pewnych pozycji wymienianych po przecinku ❤️!
UŻYCIE TYPÓW WYLICZENIOWYCH W PRAKTYCE
Przeróbmy sobie prosty przykład, do którego wstawienie wyliczenia, będzie pasować jak ulał 😄. Dajmy na to, że tworzymy grę i chcemy utworzyć do niej stopnie trudności (np. łatwy, średni, trudny), tak jak jest to powszechnie stosowane.
Mając na uwadze opis powyżej, tak będzie wyglądać "surowa" postać "enum" w języku C 👇:
enum DifficultyLevel
{
Easy, Normal, Hard
};Słowo kluczowe "enum", nazwa typu wyliczeniowego, klamerki i zestaw stałych zakończony średnikiem. To jest podstawowa struktura ✔️.
Teraz garść cennych informacji ze swej strony 😉!
CO SIĘ KRYJE ZA STAŁĄ?
Jak widzisz, mamy przypisane pozycje, dokładnie jak w liście. Mamy "Easy", "Normal" i "Hard". Jednak...w jaki sposób program może później identyfikować czym się różni jedna od drugiej 🤔?
Musisz wiedzieć, że stałe w typie wyliczeniowym są przyporządkowywane do liczb całkowitych! Domyślnie, w takiej formie w jakiej jest zdefiniowane jak u góry, poszczególne pozycje otrzymają własny numer porządkowy liczony od 0 (zera) 💡. To oznacza, że 👇:
- pod "Easy", będzie przypisana liczba 0,
- pod "Normal", będzie przypisana liczba 1,
- pod "Hard", będzie przypisana liczba 2.
W taki właśnie sposób, będzie można z łatwością rozpoznawać jaką wartość ma obecnie zmienna typu wyliczeniowego 👍!
JAWNE DEFINIOWANIE LICZBY POD STAŁĄ
Masz prawo do dostosowywania liczb jakie mają się znaleźć i pod którą stałą. Wystarczy drobny "dodatek" do definicji stałej 👇:
enum DifficultyLevel
{
Easy = 1, Normal = 2, Hard = 3
};Nie musisz dodawać jawnych przypisać do wszystkich możliwości, tylko trzeba być świadom konsekwencji jakie dotykają resztę stałych 🔥! Na przykład takie przypisanie:
enum DifficultyLevel
{
Easy = 1, Normal, Hard
};spowoduje, że po "jedynce", kolejne pozycje otrzymają kolejne numery porządkowe tj. 2 i 3. To z kolei:
enum DifficultyLevel
{
Easy = 6, Normal, Hard = 3
};przypisze pozycji "Normal" kolejny numer (7), a "Hard" będzie posiadać numer 3 💥! Taki zapis też jest dopuszczalny:
enum DifficultyLevel
{
Easy = 6, Normal = 6, Hard = 6
};aczkolwiek nie robi niczego innego poza wzbudzaniem poczucia absurdu 😅, że nie wspomnę o niepotrzebnych problemach jakie mogą powstać z tego tytułu 😏.
Przypisywanie numeru porządkowego danemu elementowi działa TAK SAMO, jak przyporządkowywanie elementów w tablicy z jawnym przypisaniem danego indeksu.
"ENUM" + "TYPEDEF" = "ENUM" NA STERYDACH
Teraz pokażę Ci coś, co gorąco zalecam stosować razem z "enum" w języku C. Chcąc utworzyć sobie zmienną bazując na typie wyliczeniowym w jego tradycyjnej formie, operowanie na takiej zmiennej nie jest takie komfortowe, jak to ma miejsce w językach o zwiększonym poziomie abstrakcji np. Java czy C# 👎.
Tam, gdzie jest możliwość odwołania się do nazwy typu i konkretnej pozycji spośród dostępnych...tu mamy jedynie "suche" liczby całkowite typu "int" 👇:
enum DifficultyLevel difficultyLevel = 3;Ponadto musisz za każdym razem dopisywać na początku słowo "enum", co też może wzbudzać irytację, jako że trzeba się przyzwyczaić do kolejnego odstępstwa od dzisiejszych norm ⚡.
Jeżeli chcesz "nagiąć" język pod dużo przyjemniejsze zapisy, dobrze skorzystać ze sztuczki z użyciem słowa kluczowego "typedef", które pozwala tworzyć aliasy dla własnych struktur danych (odrębny artykuł na ten temat, wkrótce):
typedef enum
{
Easy = 1, Normal, Hard
} DifficultyLevel;Takie "opakowanie" przynosi 2 istotne zalety 👇:
- możesz opuścić słowo kluczowe "enum" przy deklaracji zmiennej typu "enum",
- możesz zamienić przypisania liczb całkowitych na stałe.
Dla porównania z poprzednim zapisem, tak będzie wyglądać "ulepszona" definicja:
DifficultyLevel difficultyLevel = Hard;DUŻO przyjemniej 👏! Mimo faktu, iż tutaj nie piszemy pełnego odwołania do stałej, tak jak ma to miejsce w innych językach ("DifficultyLevel.Hard"), to jednak taką różnicę daje się dużo lepiej przetrawić, niż tamte u góry 👍!
Pamiętaj jednak, że wciąż możesz wstawić wartość typu "int" (i nawet spoza zakresu podanych stałych!):
DifficultyLevel difficultyLevel = 3;choć nie radzę używać liczb całkowitych, tylko kierować się wyłącznie stałymi ⚠️! Czytelność + bezpieczeństwo = kod napisany z głową 🧠.
PRZYKŁAD KODU ŹRÓDŁOWEGO
Teraz praktyka ✒️! Oto kod źródłowy prezentujący użycie typu wyliczeniowego razem z prostą obsługą zmiany przebiegu działania zależnie od wartości 🔀. Do tego zabiegu, korzystam z instrukcji "switch" osadzonej w osobnej funkcji 👇:
#include <stdio.h>
typedef enum
{
Easy = 1, Normal, Hard
} DifficultyLevel;
void printMessage(DifficultyLevel);
int main(void)
{
DifficultyLevel difficultyLevel = Hard;
printMessage(difficultyLevel);
return 0;
}
void printMessage(DifficultyLevel difficultyLevel)
{
switch (difficultyLevel)
{
case Easy:
printf("Wybrano niski poziom.\n");
break;
case Normal:
printf("Wybrano normalny poziom.\n");
break;
case Hard:
printf("Wybrano trudny poziom.\n");
break;
default:
printf("Nieznany poziom.\n");
break;
}
}Na samej górze mamy nasz typ wyliczeniowy "na sterydach" (z użyciem "typedef") 😄. Niżej znajduje się prototyp funkcji, a w samej funkcji "main", definiujemy zmienną i wywołujemy funkcję z parametrem ✔️.
Wewnątrz funkcji, definiujemy instrukcję wielokrotnego wyboru ("switch") i określamy co ma się dziać w przypadku każdej możliwej opcji. Zauważ, że uwzględniłem także sytuację, w której zmienna nie przyjmuje żadnej z dostępnych możliwości! Ponieważ wciąż możemy podstawiać liczby całkowite ("int"), a wartości mogą "wychodzić" poza stałe, musimy założyć, że może się zdarzyć przyjęcie innej opcji spośród dostępnych.
"default" to słowo kluczowe dotyczące instrukcji "switch" i pozwala na uwzględnienie scenariusza: "a co, gdy zmienna posiada wartość inną, niż wszystkie zdefiniowane przypadki powyżej?". Więcej informacji na temat instrukcji "switch" znajdziesz w załączonym artykule.
Jak sam(a) widzisz, "enum" w języku C, zwiększa bezpieczeństwo i czytelności kodu. Oczywiście, że możemy to zadanie zrealizować za pomocą samych liczb całkowitych, jednak skorzystanie z typu wyliczeniowego jest dużo lepszym rozwiązaniem ➕. Po nazwie stałej, znacznie szybciej rozpoznać jaka jest zależność, niż po samej liczbie 😉.
![]() |
Typ wyliczeniowy znany też jako "enumeracja" (albo w skrócie "enum" w języku C) to lista stałych wartości idealnie pasujących do sytuacji wyboru TYLKO JEDNEJ z dostępnych opcji.
Tyle w tym temacie 😊. Typ wyliczeniowy jak najbardziej warto znać i stosować, ponieważ sprzyja czytelności i łatwej rozbudowie w przyszłości o dodatkowe opcje 🙂.
