C/Zmienne
Procesor komputera stworzony jest tak, aby przetwarzał dane, znajdujące się w pamięci komputera. Z punktu widzenia programu napisanego w języku C (który jak wiadomo jest językiem niskiego poziomu) dane umieszczane są w postaci tzw. zmiennych, stałych i literałów. Zmienne ułatwiają programiście pisanie programu. Dzięki nim programista nie musi się przejmować gdzie w pamięci owe zmienne się znajdują, tzn. nie operuje fizycznymi adresami pamięci, jak np. 0x14613467, tylko prostą do zapamiętania nazwą zmiennej.
Czym są zmienne?
edytujZmienna jest to pewien fragment pamięci o ustalonym rozmiarze, który posiada własny identyfikator (nazwę) oraz może przechowywać pewną wartość, zależną od typu zmiennej.
Deklaracja, definicja zmiennej[1]
Typ zmiennej
edytujTyp zmiennej[2]
- określa strukturę zmiennej i danych które będziemy mogli w niej przechowywać
Typy wg złożoności
Deklaracja zmiennych
edytujAby móc skorzystać ze zmiennej należy ją przed użyciem zadeklarować, to znaczy poinformować kompilator, jak zmienna będzie się nazywać i jaki typ ma mieć. Zmienne deklaruje się w sposób następujący:
typ nazwa_zmiennej;
Oto deklaracja zmiennej o nazwie "wiek" typu "int" czyli liczby całkowitej:
int wiek;
Zmiennej w momencie zadeklarowania można od razu przypisać wartość:
int wiek = 17;
W języku C zmienne deklaruje się na samym początku bloku (czyli przed pierwszą instrukcją). |
{
int wiek = 17;
printf("%d\n", wiek);
int kopia_wieku; /* tu stary kompilator C zgłosi błąd - deklaracja występuje po instrukcji (printf). */
kopia_wieku = wiek;
}
Według nowszych standardów (C99) możliwe jest deklarowanie zmiennej w dowolnym miejscu programu (podobnie jak w języku C++), ale wtedy musimy pamiętać, aby zadeklarować zmienną przed jej użyciem. To znaczy, że taki kod jest niepoprawny:
{
printf ("Przeliczam wiek...\n");
printf ("Mam %d lat\n", wiek);
int wiek = 17; /* deklaracja po użyciu - kompilator nigdy tego nie dopuści */
}
Należy go zapisać tak:
{
printf ("Przeliczam wiek...\n");
int wiek = 17; /* deklaracja w środku bloku - dopuszczalna w C99 */
printf ("Mam %d lat\n", wiek);
}
Uwaga!
|
Jak czytać deklarację ?
edytuj- zasada spirali prawoskrętnej ( ang. The Clockwise/Spiral Rule)[3]
- zasady wg Steve Friedl'a[4]
- użyć programu cdecl: konwersja z c do języka angielskiego i w odwrotnym kierunku
Nazwa zmiennej
edytujZasady nazywania zmiennych (ang. Rules for Constructing Variable Names in C Language) [5]
- zestaw dopuszczalnych znaków
- pierwszy znak : litera lub podkreślenie ( nie zalecane z uwagi na używanie ich w nazwach zmiennych systemowych)[6]
- nie używamy słów kluczowych ( już są użyte ). Uwaga: po zmianie wielkości liter będą dopuszczalne
- wielkość liter odróżnia nazwy ( ang. case sensitive)
- długość nazwy
- do pierwszych 8 znaków
- do pierwszych 31 znaków
- niektóre kompilatory/OS pozwalają na użycie do 247 znaków[7]
Przykłady niedopuszczalnych nazw:[8][9]
1x // zaczyna się od cyfry char // słowo zarezerwowane ( ang. reserved word ) x+y // znak specjalny addition of program // spacji używać nie wolno
Cel i zasady nadawania nazw:[10]
- Wybierz słowo mające znaczenie (podaj kontekst): jednoznacznie i precyzyjnie opisywać koncept który nazywają[11]
- Unikaj nazw ogólnych (takich jak tmp)
- nazwa zmiennej nie może być taka sama jak słowo kluczowe języka C oraz jak nazwa innej zmiennej, która została wcześniej zdefiniowana w programie[12]
- Dołącz dodatkowe informacje do nazwy (użyj sufiksu lub prefiksu)
- Dołącz dodatkowe informacje do nazwy (użyj sufiksu lub prefiksu), zobacz notacja węgierska[13]
- Nie rób zbyt długich ani zbyt krótkich imion
- Używaj spójnego formatowania
Zasięg zmiennej
edytujZmienne mogą być dostępne dla wszystkich funkcji programu - nazywamy je wtedy zmiennymi globalnymi. Deklaruje się je przed wszystkimi funkcjami programu:
#include <stdio.h>
int a,b; /* nasze zmienne globalne */
void func1 ()
{
/* instrukcje */
a=3;
/* dalsze instrukcje */
}
int main ()
{
b=3;
a=2;
return 0;
}
Specyfikacja języka C mówi, że zmienne globalne, jeśli programista nie przypisze im innej wartości podczas definiowania, są inicjalizowane wartością 0.
Zmienne, które funkcja deklaruje do "własnych potrzeb" nazywamy zmiennymi lokalnymi. Nasuwa się pytanie: "czy będzie błędem nazwanie tą samą nazwą zmiennej globalnej i lokalnej?". Otóż odpowiedź może być zaskakująca: nie. Natomiast w danej funkcji da się używać tylko jej zmiennej lokalnej. Tej konstrukcji należy, z wiadomych względów, unikać.
int a=1; /* zmienna globalna */
int main()
{
int a=2; /* to już zmienna lokalna */
printf("%d", a); /* wypisze 2 */
}
Czas życia
edytujCzas życia to czas od momentu przydzielenia dla zmiennej miejsca w pamięci (stworzenie obiektu) do momentu zwolnienia miejsca w pamięci (likwidacja obiektu).
Zakres ważności to część programu, w której nazwa znana jest kompilatorowi.
main()
{
int a = 10;
{ /* otwarcie lokalnego bloku */
int b = 10;
printf("%d %d", a, b);
} /* zamknięcie lokalnego bloku, zmienna b jest usuwana */
printf("%d %d", a, b); /* BŁĄD: b juz nie istnieje */
} /* tu usuwana jest zmienna a */
Zdefiniowaliśmy dwie zmienne typu int. Zarówno a i b istnieją przez cały program (czas życia). Nazwa zmiennej a jest znana kompilatorowi przez cały program. Nazwa zmiennej b jest znana tylko w lokalnym bloku, dlatego nastąpi błąd w ostatniej instrukcji.
Uwaga!
|
Możemy świadomie ograniczyć ważność zmiennej do kilku linijek programu (tak jak robiliśmy wyżej) tworząc blok. Nazwa zmiennej jest znana tylko w tym bloku.
{ ... }
Stałe
edytujStała, różni się od zmiennej tylko tym, że nie można jej przypisać innej wartości w trakcie działania programu. Wartość stałej ustala się w kodzie programu i nigdy ona nie ulega zmianie.
W przeciwieństwie do języka C++, w C stała to cały czas zmienna, której kompilator pilnuje, by nie zmieniła się.
Stałą deklaruje się:
- z użyciem słowa kluczowego const
- dyrektywy preprocesora #define
Użycie stałej zapobiega używaniu magicznych liczb ( ang. Magic number or Unnamed numerical constants)
const
edytujconst typ nazwa_stałej=wartość;
Dobrze jest używać stałych w programie, ponieważ unikniemy wtedy przypadkowych pomyłek a kompilator może często zoptymalizować ich użycie (np. od razu podstawiając ich wartość do kodu).
const int WARTOSC_POCZATKOWA=5;
int i=WARTOSC_POCZATKOWA;
WARTOSC_POCZATKOWA=4; /* tu kompilator zaprotestuje */
int j=WARTOSC_POCZATKOWA;
Przykład pokazuje dobry zwyczaj programistyczny, jakim jest zastępowanie umieszczonych na stałe w kodzie liczb stałymi. W ten sposób będziemy mieli większą kontrolę nad kodem - stałe umieszczone w jednym miejscu można łatwo modyfikować, zamiast szukać po całym kodzie liczb, które chcemy zmienić.
Nie mamy jednak pełnej gwarancji, że stała będzie miała tę samą wartość przez cały czas wykonania programu, możliwe jest bowiem dostanie się do wartości stałej (miejsca jej przechowywania w pamięci) pośrednio - za pomocą wskaźników. Można zatem dojść do wniosku, że słowo kluczowe const służy tylko do poinformowania kompilatora, aby ten nie zezwalał na jawną zmianę wartości stałej. Z drugiej strony, zgodnie ze standardem, próba modyfikacji wartości stałej ma niezdefiniowane działanie (tzw. undefined behaviour) i w związku z tym może się powieść lub nie, ale może też spowodować jakieś subtelne zmiany, które w efekcie spowodują, że program będzie źle działał.
define
edytujPodobnie do zdefiniowania stałej możemy użyć dyrektywy preprocesora #define (opisanej w dalszej części podręcznika). Tak zdefiniowaną stałą nazywamy stałą symboliczną. W przeciwieństwie do stałej zadeklarowanej z użyciem słowa const stała zdefiniowana przy użyciu #define jest zastępowana daną wartością w każdym miejscu, gdzie występuje, dlatego też może być używana w miejscach, gdzie "normalna" stała nie mogłaby dobrze spełnić swej roli.
Literały
edytujLiterały[14], czyli stałe dosłowne.
Zawsze w programie, w którym określasz wartość jawnie zamiast odnosić się do zmiennej lub innej formy danych, ta wartość jest określana jako literał.
Literały mogą przybierać formę zdefiniowaną przez ich typ :
- całkowity
- zmiennopozycyjny
- znakowy
- napisowy
- złożony[15]
int ilosc = 23; // 23 to literał calkowity
double wysokosc = 88.2; // 88.2 to literał zmiennopozycyjny
char znak = 'c'; // 'c' jest literałem znakowym
string napis = "Napis"; // "Napis" to literał napisowy
int *p = (int []){2, 4, 6}; // literał złożony
Można użyć notacji szesnastkowej (szesnastkowej), aby bezpośrednio wstawić dane do zmiennej niezależnie od jej typu.
Podstawowe typy zmiennych
edytujKażdy program w C operuje na zmiennych - wydzielonych w pamięci komputera obszarach, które mogą reprezentować obiekty nam znane, takie jak liczby, znaki, czy też bardziej złożone obiekty. Jednak dla komputera każdy obszar w pamięci jest taki sam - to ciąg zer i jedynek, w takiej postaci zupełnie nieprzydatny dla programisty i użytkownika. Podczas pisania programu musimy wskazać, w jaki sposób ten ciąg ma być interpretowany.
Typ zmiennej wskazuje właśnie sposób, w jaki pamięć, w której znajduje się zmienna będzie wykorzystywana. Określając go przekazuje się kompilatorowi informację, ile pamięci trzeba zarezerwować dla zmiennej, a także w jaki sposób wykonywać na niej operacje.
Każda zmienna musi mieć określony swój typ w miejscu deklaracji i tego typu nie może już zmienić. Lecz co jeśli mamy zmienną jednego typu, ale potrzebujemy w pewnym miejscu programu innego typu danych? W takim wypadku stosujemy konwersję (rzutowanie) jednej zmiennej na inną zmienną. Rzutowanie zostanie opisane później, w rozdziale Operatory.
W języku C wyróżniamy następujące typy zmiennych ( wg wielkości ) :
- 4 podstawowe :
- char - jednobajtowe liczby całkowite, służy do przechowywania znaków;
- int- typ całkowity, o długości domyślnej dla danej architektury komputera;
- float - typ zmiennopozycyjny (zwany również zmiennoprzecinkowym), reprezentujący liczby rzeczywiste (4 bajty); Są dokładnie opisane w IEEE 754.
- double - typ zmiennopozycyjny podwójnej precyzji (8 bajtów);
- dodatkowe :
- typ logiczny : bool (tylko C99) (wymaga dołączenia stdbool.h) - typ logiczny
- typy złożone
Wg lokalizacji definicji typy dzielimy na :
- wbudowane, które zna kompilator; są one w nim bezpośrednio "zaszyte"
- zdefiniowane przez użytkownika typy danych. Należy je kompilatorowi opisać. Więcej informacji znajduje się w rozdziale Typy złożone.
Wg zastosowania typy możemy podzielić na :
- liczbowe
- znakowe
- char ( ang. single-byte character or byte), znak ( jednobajtowy)
- wchar (ang. wide character) = znak wielobajtowy
- łańcuchy, napis ( ang. string )
- ASCII
- Unicode
Rozmiar zmiennych można sprawdzić za pomocą prostego programu
W języku C nie jest możliwe przekazywanie typu jako argumentu |
Pojęcia związane z typami:[16]
- rodzaje typów
- grupy typów
- zgodność
- konwersje
- rozmiar
int
edytujTen typ przeznaczony jest do liczb całkowitych. Liczby te możemy zapisać na kilka sposobów:
- System dziesiętny
12 ; 13 ; 45 ; 35 itd
- System ósemkowy (oktalny)
010 czyli 8 016 czyli 8 + 6 = 14 018 BŁĄD
System ten operuje na cyfrach od 0 do 7. Tak wiec 8 jest niedozwolona. Jeżeli chcemy użyć takiego zapisu musimy zacząć liczbę od 0.
- System szesnastkowy (heksadecymalny)
0x10 czyli 1*16 + 0 = 16 0x12 czyli 1*16 + 2 = 18 0xff czyli 15*16 + 15 = 255
W tym systemie możliwe cyfry to 0...9 i dodatkowo a, b, c, d, e, f, które oznaczają 10, 11, 12, 13, 14, 15. Aby użyć takiego systemu musimy poprzedzić liczbę ciągiem 0x. Wielkość znaków w takich literałach nie ma znaczenia.
Ponadto w niektórych kompilatorach przeznaczonych głównie do mikrokontrolerów spotyka się jeszcze użycie systemu binarnego. Zazwyczaj dodaje się przedrostek 0b przed liczbą (analogicznie do zapisu spotykanego w języku Python). W tym systemie możemy oczywiście używać tylko i wyłącznie cyfr 0 i 1. Tego typu rozszerzenie bardzo ułatwia programowanie niskopoziomowe układów. Należy jednak pamiętać, że jest to tylko i wyłącznie rozszerzenie. |
W pliku inttypes.h są (od C99) zdefiniowane makra dla liczb całkowitych o stałej szerokości ( ang. Fixed width integer types ) [17]. Podstawowe typy:
- int8_t
- int16_t
- int32_t
- int64_t
- uintptr_t = typ liczby całkowitej bez znaku, który może pomieścić wskaźnik[18]
Użycie typów o stałej szerokości zwiększa przenośność programów[19]
Zobacz:
float
edytujTen typ oznacza liczby zmiennoprzecinkowe czyli ułamki. Istnieją dwa sposoby zapisu:
- System dziesiętny
3.14 ; 45.644 ; 23.54 ; 3.21 itd
- System "naukowy" - wykładniczy
pek = p*10^k = p*pow(10.0, k)
przykłady:
6e2 czyli 6 * 102 czyli 600 1.5e3 czyli 1.5 * 103 czyli 1500 3.4e-3 czyli 3.4 * 10(-3) czyli 0.0034
Należy wziąć pod uwagę, że reprezentacja liczb rzeczywistych w komputerze jest niedoskonała i możemy otrzymywać wyniki o zauważalnej niedokładności.[20]
double
edytujDouble - czyli "podwójny" - oznacza liczby zmiennoprzecinkowe podwójnej precyzji. Oznacza to, że liczba taka zajmuje zazwyczaj w pamięci dwa razy więcej miejsca niż float (np. 64 bity wobec 32 dla float), ale ma też dwa razy wyższą dokładność.
Domyślnie ułamki wpisane w kodzie są typu double. Możemy to zmienić dodając na końcu literę "f":
1.5f (float) 1.5 (double)
Specjalne wartości
edytujMożna[21] wyświetlić wewnętrzną reprezentację ( binarną i 16-ową) wartości specjalnych[22] ( dla porównania kilka niespecjalnych):
0.5: 0 01111111110 0000000000000000000000000000000000000000000000000000 0 3FE 0 0.1: 0 01111111011 1001100110011001100110011001100110011001100110011010 0 3FB 999999999999A 0.0: 0 00000000000 0000000000000000000000000000000000000000000000000000 0 0 0 NaN: 1 11111111111 1000000000000000000000000000000000000000000000000000 1 7FF 8000000000000 +infinity: 0 11111111111 0000000000000000000000000000000000000000000000000000 0 7FF 0 2^-1074: 0 00000000000 0000000000000000000000000000000000000000000000000001 0 0 1
char
edytujJest to typ znakowy, umożliwiający zapis znaków ASCII. Może też być traktowany jako liczba z zakresu 0..255. Znaki zapisujemy w pojedynczych cudzysłowach (czasami nazywanymi apostrofami), by odróżnić je od łańcuchów tekstowych (pisanych w podwójnych cudzysłowach).
'a' ; '7' ; '!' ; '$'
Pojedynczy cudzysłów ' zapisujemy tak: '\'' a null (czyli zero, które między innymi kończy napisy) tak: '\0'. Więcej znaków specjalnych.
Warto zauważyć, że typ char to zwykły typ liczbowy i można go używać tak samo jak typu int (zazwyczaj ma jednak mniejszy zakres). Co więcej literały znakowe (np. 'a') są traktowane jako liczby i w języku C są typu int (w języku C++ są typu char).
Program[23] drukuje znaki drukowalne ASCII:
// https://en.cppreference.com/w/c/language/ascii
// printtable ASCII
#include <stdio.h>
int main(void)
{
puts("Printable ASCII:");
for (int i = 32; i < 127; ++i) {
putchar(i);
putchar(i % 16 == 15 ? '\n' : ' ');
}
}
Wynik:
Printable ASCII: ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
Wewnętrzna reprezentacja znaku:[24]
printf( "%c = %hhu\n", c, ( unsigned char )c );
void
edytujSłowa kluczowego void
można w określonych sytuacjach użyć tam, gdzie oczekiwana jest nazwa typu. void
nie jest właściwym typem, bo nie można utworzyć zmiennej takiego typu; jest to "pusty" typ (ang. void znaczy "pusty"). Typ void
przydaje się do zaznaczania, że funkcja nie zwraca żadnej wartości lub że nie przyjmuje żadnych parametrów (więcej o tym w rozdziale Funkcje). Można też tworzyć zmienne będące typu "wskaźnik na void"
Specyfikatory
edytujSpecyfikatory to słowa kluczowe, które postawione przy typie danych zmieniają jego znaczenie.
signed i unsigned
edytujNa początku zastanówmy się, jak komputer może przechować liczbę ujemną. Otóż w przypadku przechowywania liczb ujemnych musimy w zmiennej przechować jeszcze jej znak. Jak wiadomo, zmienna składa się z szeregu bitów. W przypadku użycia zmiennej pierwszy bit z lewej strony (nazywany także bitem najbardziej znaczącym) przechowuje znak liczby. Efektem tego jest spadek "pojemności" zmiennej, czyli zmniejszenie największej wartości, którą możemy przechować w zmiennej.
Signed oznacza liczbę ze znakiem, unsigned - bez znaku (nieujemną). Mogą być zastosowane do typów: char i int i łączone ze specyfikatorami short i long (gdy ma to sens).
Jeśli przy signed lub unsigned nie napiszemy, o jaki typ nam chodzi, kompilator przyjmie wartość domyślną czyli int.
Przykładowo dla zmiennej char(zajmującej 8 bitów zapisanej w formacie uzupełnień do dwóch) wygląda to tak:
signed char a; /* zmienna a przyjmuje wartości od -128 do 127 */
unsigned char b; /* zmienna b przyjmuje wartości od 0 do 255 */
unsigned short c;
unsigned long int d;
Jeżeli nie podamy żadnego ze specyfikatora wtedy liczba jest domyślnie przyjmowana jako signed (nie dotyczy to typu char, dla którego jest to zależne od kompilatora).
signed int i = 0;
// jest równoznaczne z:
int i = 0;
Liczby bez znaku pozwalają nam zapisać większe liczby przy tej samej wielkości zmiennej - ale trzeba uważać, by nie zejść z nimi poniżej zera - wtedy "przewijają" się na sam koniec zakresu, co może powodować trudne do wykrycia błędy w programach.
size_t
edytujTyp size_t jest zdefiniowany w nagłówku stddef.h[25][26] jako alias do liczby całkowitej bez znaku
typedef unsigned int size_t;
Użycie size_t może poprawić przenośność, wydajność i czytelność kodu.[27]
Możemy to sprawdzić :[28]
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
przykładowy wynik :
typedef long unsigned int size_t;
short i long
edytujShort i long są wskazówkami dla kompilatora, by zarezerwował dla danego typu mniej (odpowiednio — więcej) pamięci. Mogą być zastosowane do dwóch typów: int i double (tylko long), mając różne znaczenie.
Jeśli przy short lub long nie napiszemy, o jaki typ nam chodzi, kompilator przyjmie wartość domyślną czyli int.
Należy pamiętać, że to jedynie życzenie wobec kompilatora - w wielu kompilatorach typy int i long int mają ten sam rozmiar. Standard języka C nakłada jedynie na kompilatory następujące ograniczenia:
- int - nie może być krótszy niż 16 bitów;
- int - musi być dłuższy lub równy short a nie może być dłuższy niż long;
- short int - nie może być krótszy niż 16 bitów;
- long int - nie może być krótszy niż 32 bity;
Zazwyczaj typ int
jest typem danych o długości odpowiadającej wielkości rejestrów procesora, czyli na procesorze szesnastobitowym ma 16 bitów, na trzydziestodwubitowym - 32 itd.[29] Z tego powodu, jeśli to tylko możliwe, do reprezentacji liczb całkowitych preferowane jest użycie typu int bez żadnych specyfikatorów rozmiaru.
Modyfikatory
edytujvolatile
edytujvolatile znaczy ulotny. Oznacza to, że kompilator wyłączy dla takiej zmiennej optymalizacje typu zastąpienia przez stałą lub zawartość rejestru, za to wygeneruje kod, który będzie odwoływał się zawsze do komórek pamięci danego obiektu. Zapobiegnie to błędowi, gdy obiekt zostaje zmieniony przez część programu, która nie ma zauważalnego dla kompilatora związku z danym fragmentem kodu lub nawet przez zupełnie inny proces.
volatile float liczba1;
float liczba2;
{
printf ("%f\n%f\n", liczba1, liczba2);
/* instrukcje nie związane ze zmiennymi */
printf ("%f\n%f", liczba1, liczba2);
}
Jeżeli zmienne liczba1 i liczba2 zmienią się niezauważalnie dla kompilatora to odczytując:
- liczba1 - nastąpi odwołanie do komórek pamięci. Kompilator pobierze nową wartość zmiennej.
- liczba2 - kompilator może wypisać poprzednią wartość, którą przechowywał w rejestrze.
Modyfikator volatile jest rzadko stosowany i przydaje się w wąskich zastosowaniach, jak współbieżność i współdzielenie zasobów oraz przerwania systemowe. Często jest stosowany przy tworzeniu programów na mikrokontrolery. Kompilatory często tak optymalizują kod, aby wszystkie operacje wykonywały się w rejestrach, przez co wartość zmiennej w pamięci może być przez dłuższy czas nieuaktualniana. Zastosowanie volatile zmusi kompilator do każdorazowego odwołania do pamięci w przypadku operowania na zmiennych.
register
edytujJeżeli utworzymy zmienną, której będziemy używać w swoim programie bardzo często, możemy wykorzystać modyfikator register. Kompilator może wtedy umieścić zmienną w rejestrze, do którego ma szybki dostęp, co przyśpieszy odwołania do tej zmiennej
register int liczba;
W nowoczesnych kompilatorach ten modyfikator praktycznie nie ma wpływu na program. Optymalizator sam decyduje czy i co należy umieścić w rejestrze. Nie mamy żadnej gwarancji, że zmienna tak zadeklarowana rzeczywiście się tam znajdzie, chociaż dostęp do niej może zostać przyspieszony w inny sposób. Raczej powinno się unikać tego typu konstrukcji w programie.
static
edytujPozwala na zdefiniowanie zmiennej statycznej. "Statyczność" polega na zachowaniu wartości pomiędzy kolejnymi definicjami tej samej zmiennej. Jest to przede wszystkim przydatne w funkcjach. Gdy zdefiniujemy zmienną w ciele funkcji, to zmienna ta będzie od nowa definiowana wraz z domyślną wartością (jeżeli taką podano). W wypadku zmiennej określonej jako statyczna, jej wartość się nie zmieni przy ponownym wywołaniu funkcji. Na przykład:
void dodaj(int liczba)
{
int zmienna = 0; /* bez static*/
zmienna = zmienna + liczba;
printf ("Wartosc zmiennej %d\n", zmienna);
}
Gdy wywołamy tę funkcję np. 3 razy w ten sposób:
dodaj(3); dodaj(5); dodaj(4);
to ujrzymy na ekranie:
Wartosc zmiennej 3 Wartosc zmiennej 5 Wartosc zmiennej 4
jeżeli jednak deklarację zmiennej zmienimy na static int zmienna = 0, to wartość zmiennej zostanie zachowana i po ponownym wykonaniu funkcji powinnyśmy ujrzeć:
Wartosc zmiennej 3 Wartosc zmiennej 8 Wartosc zmiennej 12
Zupełnie co innego oznacza static zastosowane dla zmiennej globalnej. Jest ona wtedy widoczna tylko w jednym pliku. Zobacz też: rozdział Biblioteki.
extern
edytujPrzez extern oznacza się zmienne globalne zadeklarowane w innych plikach - informujemy w ten sposób kompilator, żeby nie szukał jej w aktualnym pliku. Zobacz też: rozdział Biblioteki.
auto
edytujZupełnym archaizmem jest modyfikator auto, który oznacza tyle, że zmienna jest lokalna. Ponieważ zmienna zadeklarowana w dowolnym bloku zawsze jest lokalna, modyfikator ten nie ma obecnie żadnego zastosowania praktycznego. auto jest spadkiem po wcześniejszych językach programowania, na których oparty jest C (np. B).
Konwersje typów
edytujPrzypisy
- ↑ stackoverflow question: what-is-the-difference-between-a-definition-and-a-declaration
- ↑ the C data model by Jens Gustedt
- ↑ The ``Clockwise/Spiral Rule By David Anderson
- ↑ Reading C type declarations by Steve Friedl
- ↑ c4learn c-variable-nameing-rules
- ↑ Recommended C Style and Coding Standards
- ↑ Recommended C Style and Coding Standards
- ↑ about c by weebly
- ↑ Naming guidelines for professional programmers Copyright ©2017 by Peter Hilton and Felienne Hermans
- ↑ how-to-better-name-your-functions-and-variables by Friskovec Miha
- ↑ Nazwy zmiennych, notacje i konwencje nazewnicze - Mateusz Skalski
- ↑ Kurs języka C. Autor artykułu: mgr Jerzy Wałaszek
- ↑ Hungarian Notation by Charles Simonyi Microsoft Corporation Reprinted November 1999
- ↑ Literał w wikipedii
- ↑ cppreference: c language: compound literal
- ↑ cpp reference : c language - type
- ↑ cppreference: c types integer
- ↑ cppreference: integer c types
- ↑ Fixed-width_integer_types in english wiki
- ↑ The Floating-Point Guide
- ↑ | Displaying the Raw Fields of a Floating-Point Number By Rick Regan (Published May 20th, 2009)
- ↑ wartości specjalne liczbn zmiennoprzecinkowych w wiki[edii
- ↑ cppreference : ascii
- ↑ stackoverflow question: how-to-find-the-length-of-a-character
- ↑ opis size_t w cpp0x
- ↑ About size_t and ptrdiff_t, Andrey Karpov
- ↑ Why size_t matters, Dan Saks
- ↑ stackoverflow question : what-is-size-t-in-c
- ↑ Wiąże się to z pewnymi uwarunkowaniami historycznymi. Podręcznik do języka C duetu K&R zakładał, że typ int miał się odnosić do typowej dla danego procesora długości liczby całkowitej. Natomiast jeśli procesor mógł obsługiwać typy dłuższe lub krótsze stosownego znaczenia nabierały modyfikatory short i long. Dobrym przykładem może być architektura i386, która umożliwia obliczenia na liczbach 16-bitowych. Dlatego też modyfikator short powoduje skrócenie zmiennej do 16 bitów.
- ↑ wikipedia : Konwersja typu
- ↑ C++ and simple type conversion - University of CambridgeDepartment of Engineering
- ↑ frama-c : Overflow-float-integer