Szintaxis tekintetében a legnagyobb eltérés talán az, hogy a C nyelvben nagyon sokáig csak a /**/ karakterek voltak használhatóak kommentek készítésére, azonban az egy soros // kommentek a C99 szabvány óta támogatottak.
C esetén a legnagyobb különbség, hogy nincs bool típus, mivel ennek a feladatát el tudja látni az int típus is, mégpedig úgy, hogy a nullától különböző értékek igaznak tekintettek. Vagyis ha van egy ilyen feltételünk:
if (teszt) {
/*kód*/
}
Akkor, ha a teszt értéke bármi, csak nem nulla, akkor az if blokkban megadott feltétel végre fog hajtódni. Ezen viselkedés miatt különösen ajánlott minden részfeltételt zárójelezni, mivel az operátorok kiértékelési sorrendje igencsak bezavarhat.
Továbbá különösen érdemes ügyelni összehasonlításkor, hogy ténylegesen dupla = jel kerüljön a kifejezésbe, mivel az if (valami = 1) { } kifejezés figyelmeztetés nélkül lefordul és az if blokkban megadott kódrészlet mindig végrehajtásra kerül.
Ezen viselkedés inspirálta a yoda condition-nek nevezett feltétel megadási sémát. Ennek lényege, hogy az if (valami == 1) { } helyett if (1 == valami) { } formában írjuk fel a feltételeket, mert ha az utóbbi formában lemarad egy egyenlőségjel, akkor legalább fordítási hiba keletkezik.
Egy másik fontos különbség, hogy C esetén nem létezik a kivételkezelés koncepciója, így futásidőben kivételeket dobni és elkapni se tudunk. A hibák jelzésének módja a függvények visszatérési értékével szokott történni.
A kivételek hiányában nincs beépített mechanizmus az aritmetikai túlcsordulások kezelésére. Erre a programozónak kell kiváltképpen ügyelnie, mert ez biztonsági hiba is tud lenni. Egy módszer ennek elkerülésére kritikus kód esetén, hogy a szükségesnél nagyobb típussal végezzük el a műveletet. Például két 32 bites egész szorzásának eredményét 64 biten tároljuk, majd megnézzük, hogy belefér-e 32 bitbe. Ha igen, akkor minden rendben, ha pedig nem, akkor a vezérlést átugratjuk a hiba lekezeléséhez használt kódra.
int x = 971693;
int y = 1269723;
long multiply = (long)x * y;
if (multiply < INT_MAX) {
/*Minden rendben*/
}
else {
/*hiba kezelése*/
}
Az aritmetikai túlcsordulások fordítási időben sem kezeltek. Tehát például a következő értékadás forduló kódot fog eredményezni: unsigned x = -1
A hibakezelés általában if-else szerkezettel történik, de gyakran találkozhatunk goto utasítással történő ugrással is.
A goto kapcsán érdemes megjegyezni, hogy a switch-case is picit másként működik. A break utasítás hiányában a vezérlés sorban fog folytatódni. Tehát a belépési case utáni összes le fog futni, egészen addig, amíg egy break vagy return utasítással nem találkozik. Ezen hibáért a fordító szintén nem szól.
C# esetén egy kényelmi koncepció, hogy az érték alapú típusok mindig inicializálódnak egy alapértelmezett értékre. Például ha egy egész int változót létrehozunk, akkor az 0 értékről fog indulni még akkor is, ha nem írjuk ki explicit módon azt. C esetén nincs a változók létrehozásakor alapértelmezett értékadás. A változó deklarálása csupán annyit tesz, hogy a típus méretének megfelelő mennyiségű memóriát allokál a változó nevéhez. Ha ennek nem adunk értéket, akkor az éppen ott maradt szemét értéket tudjuk kiolvasni értékként. Ezért ha változókat hozunk létre, akkor minden esetben adjunk nekik értéket, mielőtt használjuk őket.
Undefined behaviour & statikus kódelemzés
A C nyelv egyik „szépsége” a nem definiált viselkedés létezése, amit angolul undefined behaviour néven szoktak emlegetni. Ezen viselkedések olyan speciális esetek, amelyek esetén nincs definiálva, hogy minek is kellene pontosan történnie, ezért fordító és platform függő, hogy mi is fog történni a program futása közben. Egy ilyen nem definiált viselkedés például az egész számok esetén a nullával való osztás.
A nem definiált működések szépsége, hogy ezeket nem kell diagnosztizálniuk a fordítóknak, ezért könnyű C-ben olyan kódot írni, ami rejtett hibákat tartalmaz. Éppen ezért erősen ajánlott valamilyen statikus kód analizáló eszközt alkalmazni, ami ezen hibák számát csökkenteni tudja. Ilyen eszköz például a Cppcheck, amit a pacman -S mingw-w64-x86_64-cppcheck parancs segítségével tudunk telepíteni 64 bites környezetben, 32 bites környezetben pedig a pacman -S mingw-w64-i686-cppcheck a parancs.
A telepítés után a kódunkat az alábbi parancs segítségével tudjuk elemeztetni:
cppcheck --enable=all --inconclusive --library=posix kod.c
A ccpcheck dokumentációja és bővebb információk a használatáról a https://cppcheck.sourceforge.io/ címen található.