[itk] Számítástechnika kezdőknek

C++ programozás kezdőknek - első lépések

[2016. szeptember 06.] [ christo161 ]

Ebben a részben elméleti alapismeretekről, és a CodeBlocks fejlesztői környezet telepítéséről és alapvető használatáról lesz szó (egy olyan programról, ami első ránézésre egy szövegszerkesztőre hasonlít, és a programozást segítő kényelmi funkciókkal van ellátva), valamint dióhéjban a parancssorban történő fordításról. Ebben a részben még nem kezdünk el programozni.

Következő rész: Az első program

Előszó

Ez a tananyag azoknak készült, akik még soha életükben nem programoztak, és nem tudják hogyan kezdjék el.
A címben a "kezdőknek" szó nem azt jelenti, hogy könnyű, hanem csak azt, hogy először az alapvető tudnivalók szerepelnek a tananyagban, lehetőség szerint egymásra épülve (ez utóbbit sajnos nem lehet tökéletesen megvalósítani, mert minden mindennel összefügg).
A tananyag elején természetesen sok olyan példaprogram szerepel, amiket már rengetegen megírtak, de ahhoz, hogy egy témában újat tudjunk alkotni, meg kell értenünk már meglévő tudnivalókat is.
Legyünk türelmesek, mert nem lehet néhány nap alatt a nulláról megtanulni C++-ul, és lehet, hogy egyes anyagrészekre többször is vissza kell térni az alaposabb megértéséhez.
Ez a tananyag akkor is hasznos lehet valakinek, ha később más programozási nyelvet választ a C++ helyett, mivel a tananyag algoritmizálási ismereteket is tartalmaz, illetve sok más programozási nyelv szintaktikája (nyelvtani szabályai) hasonlít a C++-ra.

codeblocks_hello_world.png

A tananyag különböző részeiben kiegészítő információk is találhatók. Ezek egy része nem annyira fontos, viszont gyakran tartalmaznak olyan tudnivalókat is, amik kizárólag azért kerültek a kiegészítő információk közé, mert az adott fejezet olvasásakor még nem baj, ha az olvasó nem érti őket, egy-két további fejezet elolvasását követően viszont mindenképp érdemes visszatérni rájuk.
Ne essünk pánikba, ha olyan kifejezéssel találkozunk, ami nincs rögtön elmagyarázva. Eleinte elég, ha megjegyezzük, hogy mi az eredménye az egyes példaprogramok futásának, de nem kell érteni a példaprogramokban szereplő összes utasítást, vagy kifejezést. Természetesen itt az előszóban említett fogalmakat (pl. függvény, függvénykönyvtár) szintén nem kell még érteni.
A tananyag egyes részei átugorhatók, de volt már arra példa, hogy valaki a jelen fejezetet teljesen kihagyta, mert úgy gondolta, hogy itt csak mellékes elméleti tudnivalók szerepelnek, aztán persze azt sem tudta, hogy ha a CodeBlocks-ból a fordítót nem tartalmazó verziót telepíti fel, akkor bizony CodeBlocksban nem fognak lefordulni a programok (hacsak nem telepítünk sajátkezűleg valamilyen fordítót). Szóval aki tényleg a nulláról kezd programozni tanulni, annak nem tanácsolom ezen tananyag nem folytonos olvasását, kivéve persze ha valaki egy ZH előtti este találja meg ezt a tananyagot, akkor érdemes csak a példaprogramokra fókuszálni (már ha ezt a sort elolvassa az illető :) ).

Természetesen biztos lesz, akinek ezen tananyag stílusa nem fog tetszeni, de mindenkinek tudom ajánlani a jobb oldalt található hasznos linkek oldaldobozt (mobil nézetben nem látszik). Illetve ha valaki esetleg hibát talál a tananyagban, nyugodtan jelezze hozzászólásban, vagy a facebook oldalon.

Tényleg matekzseninek kell lenni ahhoz, hogy valaki megtanulhasson programozni?

Aki programozással kezd el foglalkozni, könnyen találkozhat azzal az állítással, hogy a programozás megértéséhez nagyon kell érteni a matematikához. Ez persze attól függően igaz, hogy mit értünk az alatt, hogy nagyon, illetve hogy milyen programokat írunk.
Ezen tananyag megértéséhez nem szükséges elvégezni például az analízis (másik nevén kalkulus), diszkrét matematika, vagy lineáris algebra tantárgyakat az egyetemen, de azért alapvető matematikai ismereteket meg kell tudni érteni.
Például, hogy egy egész szám akkor páratlan ha kettővel osztva egyet ad maradékul, és akkor páros ha nullát, vagy például, hogy egy szám abszolútértéke az adott szám mínusz egyszerese, ha a szám negatív, ha pedig a szám pozitív, akkor önmaga (másképp fogalmazva a vizsgált szám mínusz előjel nélkül).
Illik ismerni az aritmetikai műveletek precedenciáját (elvégzési sorrendjét) is. Például, hogyha egy összetett aritmetikai kifejezésben nincs zárójelezés, akkor előbb a szorzást és az osztást végezzük el (ha több is van belőlük akkor balról jobbra), és csak azt követően az összeadást és a kivonást (ha több is van belőlük, akkor balról jobbra). Pl. 3-60/5/4-1=-1

Természetesen vannak ennél bonyolultabb matematikai ismereteket igénylő területei is a programozásnak, néhány példa:
grafikus keretrendszert (pl. Unreal Engine, Unity Engine) nélkülöző 3d grafika
titkosítás
statisztika
Azt azért nem garantálom, hogy a tananyag teljesen matekmentes lesz, de annyit megígérhetek, hogy a példaprogramokban nem másodfokú egyenletek megoldását vagy két szám legnagyobb közös osztóját fogjuk megkeresni. (Arra viszont senki ne számítson, hogy az első példaprogramok nagyon érdekesek lesznek és sok értelmük lesz :) ).

Tényleg elavult nyelv a C++?

Azzal az állítással is sokszor találkoztam már, hogy a C++ már elavult programozási nyelv, hiszen ott a C#, Java és egyéb újabb nyelvek. Nyilván sok hozzászólást írnak majd a látogatók egy ilyen témájú hírhez, de nem kell aggódni, C++-ra még jóideig szükség lesz, mivel számtalan program íródott C++ nyelven, melyek forráskódját jóval olcsóbb karbantartani, mint egy új nyelvre átírni, valamint a C++ nyelvhez kiadott újítások (C++11, C++14, C++17, C++20) is a nyelv létjogosultságáról tesznek tanúbizonyságot.
Természetesen a fejlesztők nem csak azért döntenek a C++ nyelv mellett, mert ha már eddig abban kódoltak, akkor nehéz lenne leváltani, hanem azért is, mert megfelelő hozzáértés esetén sokkal gyorsabban futó programokat lehet benne írni, mint egyes programnyelvekben.
"C++ code is much faster than C# code, which makes it a better solution for applications where performance is important. For instance, your network analysis software might need some C++ code, but performance is probably not a huge issue for a standard word processing application coded in C#." forrás
Porkoláb Zoltán a C programozás videósorozatának az első vagy a második videójában is említést tesz erről.

C++ nyelven tényleg csak parancssoros programokat lehet írni?

Azzal is sokan szoktak jönni, hogy C++-ban csak parancssoros programokat lehet írni. Ezt a listát tudom a figyelmükbe ajánlani.
Egy lista C++-ban írt programokról
Hasonló állítás, hogy C++-ban mindent nekünk kell megírni az alapoktól, és nem támaszkodhatunk mások által megírt függvényekre, osztályokra.
Egy lista C++-hoz használható függvénykönyvtárakról/osztálykönyvtárakról
Tény viszont, hogy bizony a legtöbb (tehát nem az összes) magyar nyelvű tananyag/tanfolyam C++-szal csak parancssoros programok szintjén foglalkozik, és csak az alapvető programozásbeli fogalmakra koncentrál (pl. változók, tömbök, elágazások, ciklusok, függvények, osztályok/objektumok, templatek/genericek, jó esetben STL).
Aki nem fél az angol tananyagoktól, az nagyon sok C++ tananyagot/ismeretet találhat nem csak parancssoros (hanem például 3d vagy ablakos) programok készítésével kapcsolatban stackoverflow-n, youtube-on, esetleg udemy-n, és biztos sok más helyen is.

A C nyelv ismerete szükséges-e a C++ nyelv megértéséhez?

Nem, de természetesen nagy előny. Illetve szinte minden programozási nyelv ismerete előny egy újabb programozási nyelv megértéséhez/megtanulásához. Az persze lehet, hogy szokatlan lesz. Például C#-ban némileg eltérő jelentése van például a static vagy a using kulcsszavaknak mint C++-ban.

Nehezebb-e a C++ nyelv?

Bár a C++ nyelv bővebb, mint a C nyelv (így ilyen szempontból nehezebb), előfordul, hogy a C nyelvben bonyolultabban lehet megoldani valamit. Jó példa erre már rögtön a parancssorba történő kiíratás (C-ben printf, C++-ban cout), illetve a dinamikus memóriafoglalás (C-ben malloc, calloc és realloc, C++-ban new, new[], delete és delete[]).
Jó eséllyel igaz az az állítás, hogy aki meg tudja tanulni az egyiket, az a másikat is.

További tévhitek a C++-ról:

A C++ legnépszerűbb mítoszai III. rész
Common Misconceptions of C++
Some popular misconceptions about C++

Alapvető tudnivalók

Ebben a tananyagban azt a tevékenységet nevezzük programozásnak, amikor egy számítógépes program forráskódját (vagy annak csak egy részét, esetleg egy új verzióját) készítjük el, legyen szó egyszerű vagy bonyolult programról. Bonyolultabb programok esetén a forráskód megírását alapos tervezés előzi meg, illetve a kód átláthatósága érdekében be kell tartani bizonyos kódolási szabályokat, szokásokat is. Természetesen a tananyag példaprogramjai annyira egyszerűek, hogy nem kell tervezgetni őket.
Arról is jókat lehet vitatkozni, hogy mi a különbség a programtervező, a fejlesztő, a kódoló és egyéb hasonló elnevezések között (egy erről szóló cikk), de itt ebbe most nem megyek bele.

A számítógép nyelve a gépi kód, amit általában 1-esek és 0-k (vagyis kettes számrendszerbeli számok) sorozataként szoktak emlegetni. A számítógép processzora csak a gépi kódú utasításokat tudja végrehajtani, és persze különböző processzortípusonként eltérő gépi kódok léteznek.
Mivel nehéz lenne gépi kódú programokat írni, ezért létrehoztak kényelmesebb, emberközelibb programnyelveket. (Ezeknek a szintjeit nem fogom pontosan kifejteni, csak két szintet említek meg. Részletesebb információ: Andrew S. Tanenbaum Számítógép architektúrák c. könyvében.)
A gépi kódú programozáshoz közelebb álló nyelveket hívjuk assembly nyelveknek, melyek használata esetén a programozó feladata hadverközeli dolgok kezelése (pl. a processzor regiszterei, megszakításkezelés). A mai magas szintű nyelvekkel ellenténben az assembly nyelvekben jellemzőek a (goto-szerű) ugróutasítások is.
Ahhoz, hogy egy adott assembly nyelven írt kódot a számítógép processzora végre tudjon hajtani, először át kell alakítani gépi kóddá. Ezt végzi el az assembler. Különböző processzortípusokhoz eltérő assembly nyelvek léteznek.
Az assemblynél könnyebben tanulható, és hardverfüggetlenebb nyelveket hívjuk magas szintű programozási nyelveknek. Ezek közé tartozik például a C, C++, C#, Java, Visual Basic, Pascal, Javasctipt, Perl, Phyton, Ruby, shell script, bash script, ... stb.
A magas szintű nyelvek létrejöttével természetesen nem szűnt meg az alacsonyabb szintek létjogosultsága. Noha magas szintű nyelveken könnyebb programozni, az alacsony szintű nyelveken viszont jobban kihasználhatjuk a számítógép hardvere által nyújtott lehetőségeket, és hatékonyabb programokat írhatunk.

gepi_kod_assembly_cpp.png

A C, és C++ nyelveket egyaránt szokták a magas szintű, és az alacsony szintű programozási nyelvek közé sorolni. Valójában magas szintű nyelvek, de alacsony szintű műveleteket, valamint bitstruktúrákat is támogatnak (sok más magas szintű programozási nyelvvel ellentétben).
Természetesen a magas szintű programozási nyelveken írt kódot is át kell alakítani gépi kóddá, ahhoz, hogy a számítógép processzora futtatni tudja, de ennek több módja is létezik, melyeknek természetesen megvannak az előnyei és hátrányai is.

  • Pl. C++ esetén a C++ nyelven írt programkódot tartalmazó fájlok (forrásfájlok) alapján egy fordító (compiler) hozza létre a gépi kódú utasításokat tartalmazó fájlokat (a futtatható programot, mely futtatásához a fordítást követően már nincs szükség a fordítóra).
    Bonyolult programok esetén a lefordított fájlokból szinte lehetetlen, de legalábbis nagyon nehéz pontosan visszafejteni a forráskódot (reverse engineering).
    Nyílt forráskódú (open source) programoknak hívják azokat, amelyeknek a forráskódját a készítők rendelkezésre bocsátják.
    Néhány példa: a Linux operációs rendszerek kernelje (magja), Firefox, Thunderbird, LibreOffice, Gimp, Blender, Audacity, VLC player, FileZilla, Notepad++, Wireshark. Több példa: egy lista nyílt forráskódú szoftverekről. Ezek forráskódja általában github.com-on található meg.
  • Pl. a Perl, Phyton, vagy a (jellemzően linuxos) shell script, vagy Bash script esetén a forráskód nem kerül lefordításra, nem jönnek létre gépi kódot tartalmazó fájlok, hanem egy értelmező (interpreter) alakítja át a program forráskódját a program futtatásának minden egyes alkalmával gépi kódra.
    Ezekhez hasonló a Javascript is, ám az esetében az internetes böngészőkbe van beépítve a Javascript értelmező.
  • Pl. a Java nyelv ebből a szempontból a fenti opciók hibridje. A fordítás által keletkező köztes kódot (bájtkódot) egy értelmező (Java Virtual Machine) futtatja.

Megjegyzés: a fent felsoroltak csak néhány szemléltető példa, egy programnyelv ezek közül akár több lehetőséget is támogathat (pl. Java kódból is lehet fordított fájlt készíteni), illetve az idők folyamán változhat a helyzet.

A C++ nyelven írt forrásfájlok gépi kódra történő fordításának lépései:

  • C++ esetén először egy úgynevezett preprocesszor végez módosításokat a programkód szövegén (pl. keresés és csere, a header fájlok tartalmának a programkódba történő beillesztése), a programkódban elhelyezett, preprocesszornak szóló (# jellel kezdődő) utasítások alapján. Ebben a lépésben még nem kezdődik meg a gépi kódra történő átalakítás.
  • Ezt követően a fordító (pl. GCC, CLang, Visual C++, stb) a C++ nyelven írt kódot tartalmazó fájlból, vagy fájlokból úgynevezett object fájlt, vagy fájlokat hoz létre, melyek már gépi kódú utasításokat tartalmaznak, de még nem futtathatóak. (Ennek előnye, hogy több fájlból álló forráskód esetén elég csak azt a fájlt újrafordítani, melynek módosítjuk a tartalmát).
  • Végül az object fájlokat a linker szerkeszti össze futtatható fájllá.

Néhány megjegyzés:

  • A GCC rövidítés (GNU Compiler Collection) egy programcsomag, mely tartalmazza a gcc-t, és a g++-t. A g++ fordítót C++ programkódok fordítására használjuk, a gcc-t pedig C programkódok fordítására. Elképzelhető, hogy valahol mégis úgy fogalmaznak, hogy "GCC fordító", de ezalatt nyilvánvalóan C kód esetén a gcc-t, C++ kód esetén pedig a g++-t kell érteni.
  • Különböző processzortípusokhoz különböző fordító készíti el a gépi kódot a forrásfájlokból. Ez akkor is így van, ha több különböző processzortípushoz is elérhető egy adott fordító (pl. GCC). Ekkor az a gépi kód, amit pl. egy x86-os processzortípushoz állítottunk elő, nem fog működni egy ARM processzoros eszközön.
  • Hasonló a helyzet a különböző operációs rendszerek esetén. Pl. egy Windowsos GCC más objectfájlokat hoz létre, mint egy Linuxos GCC. Sőt, például a grafikus felületen futó programoknak, vagy bonyolultabb parancssoros programoknak már a forráskódja is tartalmaz operációs rendszer specifikus elemeket.
  • Ha a C++ nyelven írt program csak egyetlen forrásfájlból áll, akkor is keletkezik object fájl, amiből szintén a linker hozza létre a futtatható fájlt.
  • Unix-szerű rendszereken az object fájlok kiterjesztése .o, Windowsban pedig .obj
  • Ha esetleg olyannal találkoznánk, hogy a.out, az már egy futtatható fájl, nem pedig object fájl. Akkor kapunk a.out (assembly output) elnevezésű fájlt, ha Unix-szerű rendszeren nem adunk meg nevet az indítható állománynak (például a g++ helloworld.cpp parancs esetén).
  • A fordító (illetve az értelmező) nem képes egy programkód minden hibáját felismerni. Előfordulhat, hogy noha egy helyes kifejezést írunk a programkódunkba, de ez a kifejezés mégsem azt jelenti, mint amire gondoltunk. Ennek eredményeképp ha a programunk le is fordul, lehet, hogy nem egészen úgy fog működni, mint ahogy elvárnánk.
    Az ilyen hibák felderítése nem könnyű egy több száz, vagy több ezer soros kódban, ezért jó ha tisztában vagyunk egy programozási nyelv apróbb részleteivel, illetve hogy pontosan milyen hibákat követhetünk el (erről a témáról több száz oldalas könyvek szólnak).

Manapság számos programozó nem csupán fordítót és egyéb, a fordítóhoz mellékelt programokat, továbbá valamilyen kezdetleges szövegszerkesztőt használ, hanem kényelmi funkciókkal is ellátott fejlesztői környezetet, úgynevezett IDE-t (integrált fejlesztői környezetet). Például: CodeBlocks (C::B-nek szokták rövidíteni), Microsoft Visual Studio, Apple XCode, Qt Creator, KDevelop, CLion, NetBeans, Eclipse, Geany, Anjuta, Dev-C++, C++ Builder.
Ebben a tananyagban CodeBlocks-t fogunk használni, C++ nyelven fogunk programozni, és g++ fordítót fogunk használni (ami a GCC része).
Egy fejlesztői környezet első ránézésre egy szövegszerkesztőre hasonlít. Természetesen egyéb funkciókat is tartalmaz, például ha vannak hibák a forráskódban, a fordítás megkísérlésekor kiírja, hogy melyik sorban találhatók a hibák (bár erre önmagában a fordító is képes), tartalmaz nyomkövető módot (debug), amellyel lépésenként futtathatjuk a programunkat, és ellenőrízhetjük, hogy az egyes lépésekben a változóink milyen értékeket vesznek fel. Tartalmaz továbbá kódszínezőt (syntax highlight), esetleg auto indent funkciót (egy blokkon belüli kódot automatikusan bejlebb tabulál). És persze kényelmesebb a menüből kiválasztani a fordítás elindítását (build and run), vagy egy gyorsbillentyűt megnyomni (f9), mint parancssorból fordítani.

A CodeBlocks fejlesztői környezet innen tölthető le:
http://www.codeblocks.org/downloads/binaries

CodeBlocks telepítése Windowson

Windowsban a CodeBlocks telepítése egyszerű next, next, finish-szerű telepítés. Kezdőként ügyeljünk arra, hogy a fordítót is tartalmazó telepítőfájlt töltsük le (amelyiknek a mingw kifejezés szerepel a nevében), különben a CodeBlocksban nem fogjuk tudni lefordítani, és futtatni a programjainkat (hacsak nem telepítünk és állítunk be hozzá manuálisan valamilyen fordítót).
Az idők során jó eséllyel frissebb verziójú CodeBlocks telepítőfájlokat lehet majd letölteni a honlapról, tehát a verziószám változni fog. Vagyis a telepítőfájl nevében a képen látható 16.01 helyett valami más fog szerepelni (pl. 17.12).

codeblocks_windows_mingw.jpg

A mingw a GCC Windows-os portja (windowsra megírt verziója). Tartalmazza pl. a g++ fordítót, tartalmaz linkert, assemblert (egy C++ nyelven írt programba be lehet ágyazni assembly kódot is),  a C++ Standard Library header fájljait, egyéb rendszerspecifikus header fájlokat (pl. Windows API), és egyéb összetevőket. A pontos lista itt megtekinthető: http://www.mingw.org/wiki/MinGW

A CodeBlocks nem csak Windows-on érhető el, hanem egyéb népszerűbb operációs rendszereken is. Például: OS X, Linux (pl. Debian, Fedora, CentOS, Suse, Ubuntu). A CodeBlocks honlapjának a letöltés menüpontjában megtaláljuk az egyes operációs rendszereknek megfelelő telepítőfájlokat.

CodeBlocks telepítése Linuxon

Debian és Ubuntu alapú Linux disztribúciókon (amiken van apt csomagkezelő frontend)

(Egy másik blogomon már írtam egy ismertetőt a Debian, és Ubuntu alapú linuxokon történő parancssoros telepítésről.)

codeblocks_ppa.png

A letöltéseknél az Ubuntunál láthatunk egy PPA címet:
https://launchpad.net/~damien-moore/+archive/ubuntu/codeblocks-stable

Ezt a címet kell hozzáadni az apt adatbázisához, annak érdekében, hogy a programot telepíteni lehessen. (Illetve amint új verzió érhető el, a frissítéskezelő az egyéb frissítésekkel együtt fel fogja kínálni a telepítést, valamint az apt-get update és apt-get upgrade parancsokkal szintén telepíthetjük.)

A címet át kell alakítanunk ilyen formába:
ppa:készítő_neve/program_neve, vagyis
ppa:damien-moore/codeblocks-stable
...mert az add-apt-repository parancs (amivel PPA címeket lehet hozzáadni az apt adatbázisához) csak az ilyen formájú címeket tudja kezelni.

A PPA cím apt adatbázisához való hozzáadásához, az elérhető frissítések letöltéséhez, és a CodeBlocks telepítéséhez használjuk ezt a három parancsot:

sudo add-apt-repository ppa:damien-moore/codeblocks-stable
sudo apt-get update
sudo apt-get install codeblocks

Azonban ettől a három parancstól még nem fog települni a g++ fordító, így ha azt külön nem telepítjük, a parancssorban és a CodeBlocks-ban sem tudjuk fordítani és futtatni a C++ nyelven írt programjainkat.

gplusplus_not_installed.jpg

codeblocks_gplusplus_not_installed.jpg

Érdemes telepíteni a build-essential csomagot, ami tartalmazza a gcc, és g++ fordítót is. Az ehhez szükséges parancs:

sudo apt-get install build-essential

apt_get_install_build_essentials.jpg

Hogy kezdhetünk el programot írni a CodeBlocksban?

Miután elindítottuk a CodeBlocks-ot, kattintsunk a kezdőlapon Create a new project szövegre, vagy pedig a file menüből válasszuk a New, majd a Project menüpontot.

codeblocks_new_project.png

Eleinte parancssoros programokat fogunk írni (melyek parancssorból kérik be az adatokat a felhasználótól, és a parancssorba írják ki az eredményt), így válasszuk a Console applicationt.

codeblocks_new_console_application_linux.png

Egyébként attól függetlenül, hogy egyelőre parancssorban futó programokat írunk, észrevehetjük, hogy az itt felsorolt lehetőségek némileg eltérőek a különböző operációs rendszereken (pl. Windowson és Linuxon). Ez azért van, mert például az ablakos, vagy 3D-s programok írása jellemzően eltérő módon valósítható meg különböző operációs rendszereken. Néhány példa:

Windows API: ablakos programok (Windows)
Windows Forms: ablakos programok (Windows)
GTK: ablakos programok (több platform)
Qt: ablakos programok (több platform)
SDL: 2D és 3D programozás, jellemzően játékok (több platform)
DirectX: 3D programozás (Windows)
OpenGL: 3D programozás (több platform)
Vulkan: 3D programozás (több platform)

Egyrészt kezdőknek tanácsos először parancssoros programokat írni, és azok segítségével megérteni az alapokat.
Továbbá a fentebb felsoroltakhoz nem a CodeBlocks a legszerencsésebb választás. (Pl. Windows Formshoz Visual Studio, Qt-hoz pedig Qt Creator).

codeblocks_new_console_application_win.png

Ebben a tananyagban a C++ programozási nyelvet fogjuk használni, így válasszuk a C++-t.

codeblocks_new_project_step_1.png

Ezt követően a legfelső szövegmezőben nevezzük el a projektünket (pl. elso_programnak), majd egyel lejjebb, a ... feliratú gombra kattintva válasszunk ki egy könyvtárat, ahová el szeretnénk helyezni a projekt könyvtárát (ami tartalmazni fogja a programunkhoz tartozó forrásfájlokat, a fordítást követően keletkező fájlokat, és egyéb fájlokat, például a projekt beállításait tartalmazó fájlt).
FONTOS: ne szerepeljen szóköz vagy ékezet sem az elérési útban, sem a projektnévben (sem pedig a projekt azon fájljainak nevében, amiket a több fájlból álló projektek esetén a projekthez majd később hozzáadunk).

codeblocks_new_project_step_2.png

A következő lépésnél kiválaszthatjuk a fordítót (alapesetben a GCC programcsomag fordítói vannak kiválasztva: gcc és g++), illetve megadhatjuk, hogy a projekt könyvtárán belül milyen könyvtárba jöjjön létre a programunk forráskódja alapján készített futtatható állomány, illetve a fordítás közbeeső lépésének fájljai.
Kezdőként itt semmit nem kell átállítani, rákattinthatunk a Finish gombra.

codeblocks_new_project_step_3.png

Ekkor a CodeBlocks a projekt könyvtárában létrehoz egy main.cpp nevű forrásfájlt, amiben egy nagyon egyszerű programkódot helyez el (Hello World! szöveg kiíratása a parancssorba). Ezt a fájlt úgy nyithatjuk meg, ha a baloldali panelen duplán kattintunk a sources mappára, majd a main.cpp fájlra.

codeblocks_open_main_cpp.png

Amikor majd programot írunk, elsősorban ennek a main.cpp fájlnak írjuk át a tartalmát, illetve az egyszerűbb (egy fájlból álló) példaprogramok kódját ebbe a fájlba másolhatjuk be (akár a fejlesztői környezet segítségével, vagy akár egy egyszerű szövegszerkesztővel, viszont formázást használó szövegszerkesztőt (pl. Microsoft Word, Wordpad, OpenOffice, LibreOffice) erre a célra ne használjunk).
Az ebben a fájlban található main függvény a programunk belépési pontja. A program érdelmi tartalma (vagyis amit a program valójában csinál) a main függvény első utasításával kezdődik (akkor is, ha a forráskód több fájlból áll).
(Ne tévesszük össze a main.cpp fájlt a main függvénnyel. A main.cpp fájlt nevezhettük volna másképp is, pl elsoprogram.cpp-nek, viszont a main függvényt nem nevezhethük át, különben a program nem fog lefordulni. A CodeBlocks alapértelmezetten main.cpp-nek nevezi el az egyszerű parancssoros program main függvényt tartalmazó fájlját, de természetesen ezt is módosíthatjuk.)

A fordításhoz, és egyúttal a program futtatásához válasszuk a Build menüből a Build and run menüpontot, vagy használjuk az F9 gyorsbillentyűt (mindkét esetben mentésre kerülnek a forráskódban végzett módosítások).

codeblocks_build_and_run.png

Ekkor (ha nincs a fordító által észlelhető hiba a programban) a program futásának eredménye egy parancssoros ablakban lesz látható. Amikor a program futása véget ér, a parancssoros ablak nem tűnik el azonnal, hanem csak egy Enter billentyű leütését követően. De ez csak a fejlesztői környezetben van így. Ha a Windows fájlkezelőjében duplán kattintunk a program futtatható fájljára (pl. elso_program.exe), akkor a megnyíló parancssoros ablak a program futását követően azonnal bezárul. A későbbiekben lesz szó ennek a problémának a megoldásáról is. 

codeblocks_hello_world.png

C++11 szabvány

A C++11 szabvány (korábbi nevén C++0x) 2011 szeptemberében jelent meg, sok újdonságot és módosítást tartalmaz (például új típusokat, új vagy módosított kulcsszavakat).
Bővebb információ: [1] [2]

Ha azt szeretnénk, hogy egy CodeBlocks projektünket a fordító a C++11-es szabvány szerint fordítsa le, akkor a bal oldali panelen jobb gombbal kattintsunk a megnyitott projekt nevére, majd válasszuk a Build options menüpontot...

cpp11_build_options.png

...majd a megnyíló ablakban jelöljük be a Have g++ follow the C++11 ISO C++ language standard lehetőséget.

cpp11_build_options_2.png

Ha ezt nem tesszük meg, de a forráskódunk tartalmaz olyan kódrészletet, ami csak a C++11-es szabvány szerint érvényes, akkor a program nem fog lefordulni (a fordító nem fogja elkészíteni az indítható állományt).

Hasonlóan járhatunk el a C++14, C++17 és C++20 verziókkal.

Egyéb: egy CodeBlocks projekt könyvtára és fájljai

Alapbeállítás szerint a lefordított fájl a projekt könyvtárán belüli bin könyvtárban jön létre.

codeblocks_project_files.jpg

A projekt könyvtárában találhatjuk a program forráskódját, a main.cpp-t is (később majd lesznek olyan programjaink is, amik nem csak ebből az egy fájlból állnak).
A .cbp kiterjesztésű fájl a CodeBlocks projekt fájl, ha erre duplán kattintunk, a projekt megnyílik a CodeBlocksban. Ez és a többi fájl egyéb beállításokat tartalmaz a CodeBlocks projektre nézve, a tényleges forráskódot a .cpp, .h, esetleg .cxx, .hxx, .hpp kiterjesztésű fájlok tartalmazzák.

Egyéb: online C++ fordítók

Számos honlap létezik, ahol a C++ kódunkat beírva a futtatás eredményét megtekinthetjük. Ez hasznos lehet, ha például egy olyan számítógépet használunk, ahol nincs jogosultságunk, vagy időnk programokat telepíteni (pl. iskola, munkahely, kávézó).

cpp_online.png

Egyéb: tetszőleges terminál beállítása Linuxon

Linuxon azt is be lehet állítani, hogy melyik parancssoros programban futtassa a CodeBlocks a fordítást követően a programot.

codeblocks_cli_types.png

Például Ubuntuban a gnome-terminalt használva:

codeblocks_gnome_terminal.png

Fordítás parancssorban

Windowsban:

A billentyűzetünkön nyomjuk meg egyszerre a windows gombot és az R billentyűt, majd a felugró ablakba (futtatás) írjuk be, hogy cmd és üssünk entert.
Ekkor elindul a parancssor.
(Persze kikereshetjük valamilyen menüből is a parancssort, csak ahány Windows verzió, annyi különböző módszer van már erre).

Lépjünk be abba a könyvtárba, ahol a lefordítandó cpp fájlunk található.
Itt futtassuk a következő parancsot:
g++ bemenetifájlnév -o kimenetifájlnév.
Példa:

g++ elsoprogram.cpp -o elsoprogram.exe

A bemeneti fájlnév annak a fájlnak a neve, amit fordítani szeretnénk (a forrásfájl), a kimeneti fájlnév pedig a programkódból keletkező indítható fájl. A kimeneti fájlnév kiterjesztése szükségszerűen exe, mivel a Windowsban az indítható állományok leggyakoribb kiterjesztése exe.
Ha több bemeneti fájl van, akkor azokat szóközzel elválasztva soroljuk fel egymás után.
(C++11-es szabvány szerint érvényes kódrészletet tartalmazó forráskód esetén a fordításhoz használt parancsban a sikeres fordításhoz szerepelnie kell az std=c++11 kapcsolónak, a fájlparaméterek előtt:
g++ -std=c++11 bemenetifájlnév -o kimenetifájlnév)

windows_cli_compile.png

Tipikus hiba, hogy a rendszer nem találja a g++-t. Van egy környezeti változó (path), ahová ha beírjuk egy könyvtár elérési útját, akkor az abban a könyvtárban lévő indítható állományok (pl. exe, com, bat kiterjesztésű fájlok) bármelyik könyvtárból elindíthatóak lesznek az elérési útjuk megadása nélkül is.
Amikor telepítettük a CodeBlocks-ot, az egyik alkönyvtárába települt a g++.exe fájl is. Ahol ez a fájl van, annak a könyvtárnak az elérési útját kell hozzáfűznünk az említett környezeti változóhoz.

Ezt parancssorban például úgy tehetjük meg, hogy belépünk abba a könyvtárba, aminek az elérési útját hozzá szeretnénk adni a pathhoz, és itt kiadjuk a következő parancsot:
set path=%path%;%cd%
Ebben az esetben a változtatás csak addig él, amíg be nem zárjuk a parancssort. Ha azt szeretnénk, hogy a változtatás tartós legyen, akkor a vezérlőpultban nyissuk meg a számítógép beállításait (vagy használjuk a windows gomb + pause break gyorsbillentyűt), majd válasszuk a rendszer menüpontot, ott pedig a környezeti változók feliratú gombra kattintsunk. Itt az alsó listában megtaláljuk a path-ot, és át tudjuk szerkeszteni. Az egyes könyvtárak elérési útjai pontosvesszővel vannak elválasztva egymástól.

windows_set_path.png

Linuxon:

Nyissunk meg egy parancssoros felületet (Ubuntuban például ctr+alt+t vagy ctr+alt+f1, mely utóbbi esetén alt + f7-el tudunk visszalépni grafikus felületre), lépjünk be abba a könyvtárba, ahol a lefordítandó cpp fájl található
Itt futtassuk a következő parancsot:
g++ bemenetifájlnév -o kimenetifájlnév. Például:

g++ main.cpp -o elsoprogram

Ha több bemeneti fájl is van, akkor azokat szóközzel elválasztva tudjuk felsorolni.
A kimeneti fájlnak nem szükséges kiterjesztést adni (mint Windowsban), mivel a Linux alapú operációs rendszerek nem igénylik, hogy a fájlneveknek kiterjesztése legyen. Azért van mégis egyes fájloknak kiterjesztése Linuxon is, mivel vannak olyan alkalmazások, amik viszont igénylik a kiterjesztések használatát.
C++11-es szabvány szerint érvényes kódrészletet tartalmazó forráskód esetén a fordításhoz használt parancsban a sikeres fordításhoz szerepelnie kell az std=c++11 kapcsolónak:
g++ -std=c++11 bemenetifájlnév -o kimenetifájlnév

linux_gcc_cli_compile.jpg

A lefordított programot parancssorban így futtathatjuk:

./fájlnév

linux_cli_execute.jpg

A fájlnév előtt az aktuális könyvtárat valójában csak akkor kell jelölni, ha az aktuális könyvtár elérési útja nem szerepela PATH környezeti változóban. Mivel a saját könyvtárunk az alkönyvtáraival együtt szerepel a PATH változóban, így sokszor nem szükséges az aktuális könyvtár kiírása egy indítható fájl parancssorban történő futtatásakor, de nem hátrány, ha megszokjuk a használatát.

Esetleg előfordulhat, hogy a lefordított fájlon nem lesz futtatási jog, és így hibaüzenetet kapunk az indítás megkísérlésekor. Erről úgy tudunk meggyőződni, hogy az ls -al paranccs által megjelenített listában az adott fájlhoz tartozó első oszlop nem tartalmaz x karaktereket. Ekkor használjuk a chmod u+x ./fájlnév parancsot. Ezen parancs futtatásához lehet, hogy rendszergazdai jogosultság szükséges.

Kiegészítő információk

Amikor CodeBlocksban rákattintunk a Build and Run ikonra, vagy megnyomjuk az F9 billentyűt, a Build Logban megfigyelhetjük, hogy a CodeBlocks a következő parancsokat futtatja (alapbeállítás szerint):

g++ -Wall -fexceptions -g -c elérési_út/main.cpp -o obj/Debug/main.o
g++ obj/Debug/main.o -o bin/Debug/projektnév

Az egyszerűbb áttekintés érdekében tekintsük a parancsokat extra kapcsolók nélkül:

g++ -c elérési_út/main.cpp -o obj/Debug/main.o
g++ obj/Debug/main.o -o bin/Debug/projektnév

Ezen két utóbbi parancs csupán annyiban különbözik a fentebb már említettől (g++ main.cpp -o elsoprogram), hogy nem csak futtatható állományt hoz létre, hanem egy közbeeső object fájlt is.

Az első utasítás első paraméterében megadjuk a forrásfájlt, majd az -o (output file rövidítése) kapcsolót követően a létrehozni kívánt object fájl nevét (a -c kapcsoló ahhoz szükséges, hogy az első lépésben csak az object fájl jöjjön létre, a linkelés még ne történjen meg).
A második utasításban pedig első paraméterként adjuk meg a létrehozni kívánt indítható állomány (a projekt könyvtárához képesti) elérési útját és nevét, második paraméterként pedig az object fájl (projekt könyvtárához képesti) elérési útját.

A CodeBlocks alapbeállításai által használt további kapcsolók jelentése:

-Wall: ne csak a fordítási hibákat (angolul error) írja ki a fordító, hanem a lényegesebb figyelmeztetéseket (warning) is.

error: nem fordul le a program, ha ilyen típusú hiba szerepel a forráskódban
warning: ha csak ilyen hibát tartalmaz a forráskód, a program lefordul, de lehet, hogy hibás működést fog eredményezni, illik kijavítani az ilyen típusú hibákat is

-fexceptions: kivételkezelés ( azaz try { } catch ( ) { } blokkok ) engedélyezése a forráskódban. C++ kód esetén ez akkor is érvényes, ha nincs megadva (C kód esetén viszont nem), ha esetleg C++ kódban tiltani szeretnénk a kivételkezelést, akkor az -fno-exceptions kapcsolót használhatjuk.

-g: a debug (nyomkövető) mód használatához plusz információk elhelyezése a kódban. A fájlok mérete nagyobb lesz, így a felhasználók számára közzétett verzió fordításakor érdemes kikapcsolni.

Egyéb kapcsolók:

-Wextra: a fordító az összes warningot kiírja, nem csak a lényegesebbeket.

-pedantic: a fordító hibaüzenetben kiírja a kód nem szabványos részeit. Nem szabványos kódrészlet az, amit bizonyos fordítók engedélyeznek, de előfordulhat, hogy egyes fordítók nem támogatják. Egy példa:
int elemszam;
cin >> elemszam;
int tomb[elemszam];
Ezt például a g++ elfogadja, de példaául a Microsoft Visual Studio fordítója nem (erről a kódrészletről a tömbök fejezetben lesz szó részletesebben). A kód hordozhatósága miatt javasolt a forráskódnak lehetőség szerint csak szabványos kódrészletet tartalmaznia.

-std=c++11: a forráskód C++11-es szabvány szerinti értelmezése.

-O3 (nem nulla, hanem nagy o betű): a fordító a sebességre optimalizálja a kódot.

-Os: a fordító az alacsony helyfoglalásra optimalizálja a kódot.

Ezeket a kapcsolókat természetesen parancssorban történő fordításnál is használhatjuk, és a CodeBlocksban is beállíthatjuk, ugyanabban a menüben, ahol a C++11-et (lásd fentebb).

A fordítás egyes lépéseinek eredményei:

Az előfordítás eredményét kiíratjuk a parancssorba (ez általában több ezer sor, így érdemesebb inkább fájlba menteni):

g++ -E fajlnev.cpp

Az előfordítás eredményét bemásoljuk a fajlnev.txt nevű fájlba:

g++ -E fajlnev.cpp > fajlnev.txt

(Ha már létezik ilyen nevű fájl > jel esetén felülírja, >> jel esetén pedig a tartalmához hozzáfűzi).

gpp_e.png

Az assembly kóddá történő fordítás eredményét menjük el a fajlnev.s nevű fájlba:

g++ -S fajlnev.cpp

gpp_s.png

Az object fájllá történő fordítás eredményét kapjuk meg a fajlnev.o (Windowson fajlnev.obj) nevű fájlba:

g++ -c fajlnev.cpp
g++ -c fajlnev.cpp -o fajlnev.o

Ha a programunk több forrásfájlból áll, akkor természetesen nem készíthető minden forrásfájlból egy-egy indítható állomány, hanem az egyes forrásfájlokat object fájllá tudjuk külön-külön lefordítani (akár anélkül, hogy a többi fájlt is le kellene fordítani), majd az összes object fájlból készülhet el az indítható állomány. (A DLL, illetve SO kiterjesztésű fájlokról csak a tananyag későbbi részében lesz szó.)

Indítható állomány létrehozása:
Unix-szerű rendszereken:

g++ fajlnev.cpp -o fajlnev

Windowson:

g++ fajlnev.cpp -o fajlnev.exe

Következő rész: Az első program

A bejegyzés trackback címe:

https://itkezdoknek.blog.hu/api/trackback/id/tr167746690

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.