Search
Účelem prvního cvičení je získat funkční prostředí pro kompilaci C++14. U Linuxu je třeba rozlišovat mezi kompilátorem (vezme kód, vyplivne spustitelný program) a IDE (usnadňuje psaní kódu), ale Windows i OS X mají silně spjaté kompilátory s IDE.
Ať už čekáte, než se vám nainstaluje prostředí (ani XCode, ani VS s instalací zrovna nespěchají), nebo byste si chtěli vyzkoušet kompilátor, ke kterému aktuálně nemáte přístup, internetové kompilátory umožňují rychle vyzkoušet jednoduché programy. Existuje jich více, ale nejčastěji používáme Coliru.
Náš nejoblíbenější online kompilátor, i když není zrovna nejintuitivnější. Kompilace více souborů je… zajímavá a způsob zadávání vstupu na stdin též. Základní ovládání je jednoduché, jak zkompilovat více souborů nebo jak zadat vstup najdete v Coliru FAQ
Ideone umožňuje snadno zadat vstup programu a podporuje více jazyků než jen C++. Aktuální kompilátory tam ale najdete se zpožděním a nelze u něj měnit kompilační parametry.
Godbolt gcc je online kompilátor, ve kterém sice nemůžete kód spouštět, ale můžete se podívat, do čeho se zkompiluje. Snadný způsob, jak se podívat, co kompilátor opravdu při optimalizaci provede.
I Visual C++ má svůj kompilátor online. Bohužel, kvalita implementace se zdá být nízká, většina našich pokusů skončila s Maximum execution time exceeded!. Snad časem.
Maximum execution time exceeded!
Uvedený výčet samozřejmě není kompletní, chybí v něm například cppshell.
Většina lidí nejradši pracuje na svém vlastním počítači. Připravili jsme pro vás krátký návod, co a odkud nainstalovat na jaké platformě.
Pro linux doporučujeme Clang jako váš hlavní kompilátor. Nicméně protože na Linuxu Clang používá libstdc++, což je standardní knihovna GCC, potřebujete primárně aktuální verzi GCC. Cílové verze jsou GCC 5.2+, Clang 3.6+.
Existuje mnoho různých IDE, která běží pod Linuxem, počínaje KDevelop (které je silně svázané s KDE balíčky), přes CodeBlocks, Eclipse CDT, Netbeans, QT Creator, až po CLion.
Pokud používáte OS X, k získání kvalitního kompilátoru vám “stačí” nainstalovat XCode. XCode vyžaduje ke stáhnutí Apple ID a má 4.5GB, takže se připravte, že instalace chvíli zabere.
Pokud ho ještě nemáte, Apple ID si můžete vytvořit zde. XCode pak můžete stáhnout z AppStore nebo zde ve verzi 7.2.1.
Pokud používáte Windows, velmi silně doporučujeme Visual Studio 2015, specificky v Community edition, která je zdarma a smí se nadále používat i pro komerční účely1). Pozor, již neplatí, že studenti katedry počítačů mají přístup ke MSDNAA licencím pro software od Microsoftu.
Instalační soubory samotné naleznete zde, k používání VS 2015 Community Edition déle než 30 dní potřebujete účet, který si můžete vytvořit zde.
CLion je komerční2) multiplatformní IDE od JetBrains pro C++. Pokud používáte jiné JetBrains produkty, jeho ovládání a vzhled vám budou dobře známé, ale osobně preferuji VS2015 kvůli kvalitnějšímu napovídání při používání typové inference a C++14.
MinGW rozhodně nedoporučujeme. Zatímco kompilátor funguje a core language má dobrou podporu, standardní knihovny v sobě mají zásadní díry. Historicky Regex a Random nefungovaly (Random má stále problémy) a například tento triviální program se pod mingw nezkompiluje kvůli chybějícím knihovná(defaultní instalace má chybu v balíčkování, dá se vyřešit)).
#include <string> #include <iostream> int main(){ int i = 12412; auto s = std::to_string(i); std::cout << "Cool number: " << s << std::endl; }
Pokud chcete, můžete používat Cygwin. GCC pod Cygwinem netrpí problémy MinGW toolchainu, ale předem říkáme, že jsme s ním úlohy netestovali, takže z naší strany nedáváme žádné záruky.
V místnostech používaných pro cvičení je při bootu k dispozici Ubuntu, kde najdete Clang ve verzi 3.8, g++ ve verzi 5.3.0, Netbeans, Eclipse a samozřejmě základní linuxí utility. Jako IDE doporučujeme Netbeans, kde si budete muset aktivovat C/C++ plugin, jako čistý textový editor můžete použít třeba Gedit (nebo všudypřítomné vi/nano).
Ubuntu
Pokud budete používat Netbeans, nezapomeňte si nastavit nástroje na Clang a standard jazyka na C++14
Před prvním přihlášením si budete muset nastavit heslo.
Základní výstup (tisk do konzole) funguje v C++ přes tzv. “streamy” (proudy). Konzolový výstup (stdout) je reprezentován objektem std::cout, vstup (stdin) je pak reprezentován objektem std::cin.
std::cout
std::cin
Tato ukázka reprezentuje minimální program “Hello world”. Po jeho vykonání bude na konzoli napsáno Hello World.
#include <iostream> int main(){ std::cout << "Hello world\n"; }
#include <iostream>
Tento program ukazuje načítání vstupu.
#include <iostream> int main(){ std::cout << "Dej mi cislo\n"; int num; std::cin >> num; std::cout << "Cislo bylo: " << num << '\n'; }
std::cin >> num;
Všimněte si, že se operátor výstupu dá řetězit. Stejným způsobem se dá řetězit i čtení:
int num1, num2; std::cin >> num1 >> num2
Jakmile začneme mít více kódu, je dobré ho rozdělit do více souborů. “Hello world” sice není zrovna složitý program, ale jako ukázka nám poslouží.
Mějme 5 souborů: main.cpp, hello.h, hello.cpp, world.h, world.cpp s obsahem: main.cpp
main.cpp, hello.h, hello.cpp, world.h, world.cpp
#include "hello.h" #include "world.h" int main(){ say_hello(); say_world(); }
hello.h
void say_hello();
hello.cpp
#include <iostream> void say_hello() { std::cout << "Hello "; }
world.h
void say_world();
world.cpp
#include <iostream> void say_world(){ std::cout << "world\n"; }
{
}
Deklarace je způsob jak říci, že určitá funkce existuje a smí se používat, i když je součástí jiného souboru. Alternativně se na ni dá nahlížet jako na způsob, jak slíbit, že nějaká funkce bude “časem” existovat. Definice pak je kompletní funkce a v programu může být každá funkce definována pouze jednou3). Deklarací může program obsahovat libovolné množství.
Nebudeme zatím řešit standardní knihovnu nijak do hloubky, ale krom standardního vstupu a výstupu se ještě podíváme na dva kousky standardní knihovnu. Třídu pro řetězce, std::string, která zjednodušuje práci s řetězci, a std::vector, což je třída podobná javovské třídě ArrayList.
std::string
std::vector
ArrayList
std::string se dá načítat přes std::cin a vypisovat přes std::cout. Pozor, načítání funguje po “slovech”, tj. načtou se všechny znaky mezi dvěma prázdnými místy (mezery, tabulátory, konce řádků…).
Co to znamená? Mějme tento kousek kódu:
#include <iostream> int main() { std::cout << "Napis sve jmeno:\n"; std::string jmeno; std::cin >> jmeno; std::cout << "Ahoj " << jmeno << '\n'; }
Jan
Napis sve jmeno: Jan Ahoj Jan
Jan Novak
Napis sve jmeno: Jan Novak Ahoj Jan
std::vector je rostoucí pole. Není potřeba předem určit velikost, stačí vytvořit vektor a přidávat/odebírat prvky dle libosti. Jedná se o šablonovou třídu, což znamená, že je potřeba deklarovat, jaký typ chceme do vektoru ukládat.
Do vektoru můžeme ukládat primitivní i uživatelem definované typy.
#include <iostream> #include <vector> int main() { std::vector<int> numbers; std::cout << "Napis 5 cisel.\n"; for (int i = 0; i < 5; ++i){ int temp; std::cin >> temp; numbers.push_back(temp); } std::cout << "Cisla byla:\n"; for (int i = 0; i < 5; ++i){ std::cout << numbers[i] << '\n'; } }
Předchozí ukázka nejdříve načetla 5 čísel a pak vypsala prvních 5 prvků z vektoru. Co by se ale stalo, pokud bychom změnili načítací smyčku, aby načítala pouze 4 prvky? Není to jisté, protože to je tzv. nedefinované chování4), ale důležité je, že bychom smyčky, kde chceme přejít přes celý kontejner, měli psát trochu jinak.
#include <iostream> #include <vector> #include <string> int main() { std::vector<std::string> vec; std::cout << "Zadej 5 jmen.\n"; for (int i = 0; i < 5; ++i){ std::string temp; std::cin >> temp; vec.push_back(temp); } std::cout << "Jmena byla:\n"; for (std::string s : vec){ std::cout << s << '\n'; } }
... std::cout << "Jmena byla:\n"; for (auto s : vec) { std::cout << s << '\n'; }
auto
Pojem nedefinovaného chování (UB – Undefined Behavior) v C++ vyjadřuje situaci, ke které dle standardu jazyka “nemůže dojít”. Pozor, to neznamená, že jazyk brání tomu, aby k nim došlo, ale kompilátor při optimalizacích může nedefinované chování zanedbat a předpokládat, že si programátor “nějak” zajistil, aby k němu nedošlo.
Co to znamená v praxi, si ukážeme na několika příkladech.
Zkuste si zkompilovat a spustit tento program, nejdříve bez optimalizací:
#include <iostream> int main(){ int i = 1; while (i > 0){ std::cout << "Ahoj\n"; i *= 2; } }
-O3
Release
Zkuste si zkompilovat a spustit tento program. Nezapomeňte zapnout C++14.
#include <iostream> int test(int x) { if (x > 0) { return 1; } x -= 1'000'000'000; if (x > 0) { return 2; } return 1; } int main(){ std::cout << test(1) << std::endl; std::cout << test(-2'000'000'000) << std::endl; }
Možná jste slyšeli o Velké Fermatově větě. Dlouho se nevědělo, jestli je opravdu pravdivá, nebo ne, ale v roce 1995 se ji po dlouhé době podařilo prokázat. Představte si, že tomu důkazu nevěřite a chcete si ji ověřit.
Tento kousek kódu5) ji vyzkouší pro n == 3 a a, b, c <= 1000. Zkuste si ho zkompilovat s optimalizacemi.
n == 3
a, b, c <= 1000.
#include <iostream> bool fermat() { const int MAX = 1000; int a = 1, b = 1, c = 1; while (true) { if ((a*a*a) == ((b*b*b) + (c*c*c))) { return true; } a++; if (a > MAX) { a = 1; b++; } if (b > MAX) { b = 1; c++; } if (c > MAX) { c = 1; } } return false; } int main() { if (fermat()) { std::cout << "Fermat's Last Theorem has been disproved.\n"; } else { std::cout << "Fermat's Last Theorem has not been disproved.\n"; } }
Video Tutorial: https://www.youtube.com/watch?v=Cq1h1KPoGBU