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 👇:

  1. pod "Easy", będzie przypisana liczba 0,
  2. pod "Normal", będzie przypisana liczba 1,
  3. 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 👇:

  1. możesz opuścić słowo kluczowe "enum" przy deklaracji zmiennej typu "enum",
  2. 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 "enum" w języku C

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 🙂.

PODOBNE ARTYKUŁY