Překlad jazyka C Plus Plus
Z CHWiki
C a C++ jsou poměrně nízkoúrovňové jazyky a vedle problémů s programem samotným mívají začátečníci i problémy s překladem. Většinou nestačí použít k řešení intuici a je třeba vědět, jak v C/C++ probíhá překlad. V obou jazycích je základní proces v podstatě stejný.
Překlad má následující základní fáze:
- Předzpracování zdrojového kódu (preprocessing)
- Překlad jednotlivých zdrojových souborů (compilation)
- Spojování (linking)
Obsah |
[editovat] Předzpracování (preprocessing)
Tuto fázi zajišťuje program zvaný preprocessor. Projde všechny zdrojové soubory a provede expanzi maker a zpracuje instrukce pro preprocessor. Tyto instrukce vždy začínají znakem # na začátku řádku. Nejčastěji se používají tyto instrukce:
#include "soubor.h"
Tato instrukce vloží celý obsah soubor.h na dané místo.
#define MAKRO obsah
Tato instrukce nadefinuje makro s názvem MAKRO a jako jeho obsah nastaví obsah. Kdekoliv se potom ve zdrojovém souboru bude vyskytovat řetězec MAKRO, bude nahrazen obsahem tohoto makra. Makra mohou mít i parametry.
#ifdef MAKRO
Pokud je makro s názvem MAKRO definováno, bude následující kód ponechán, jinak bude až do #endif odstraněn.
Do překladače jde až zpracovaný zdrojový kód.
[editovat] Překlad (compilation)
Předzpracované zdrojové soubory (ty s příponou cpp nebo c) jsou jeden po druhém přeloženy překladačem do tzv. objektových souborů (přípona .obj nebo .o, nijak to nesouvisí s objektově orientovaným programováním). Každý soubor je přeložen zvlášť a nezávisle na ostatních. Funkce, objekty a proměnné mají v objektovém souboru svůj název (který může být ale překladačem pozměněn, především v případě C++).
Z toho důvodu nemůže překladač odhalit, když jsou dvě proměnné stejného jména deklarované ve dvou souborech a podobně.
[editovat] Spojování (linking)
Nakonec linker vezme objektové soubory a spojí je do jednoho spustitelného souboru nebo knihovny. Během tohoto procesu nahradí odkazy pomocí názvů konkrétními adresami.
V této fázi lze detekovat duplicitní funkce, proměnné a podobně.
[editovat] Obvyklé problémy
- Unresolved external symbol ...
- Tuto chybu hlásí linker když v objektovém souboru najde odkaz na funkci nebo proměnnou, která není nikde definována. Typicky je to v případě, kdy v jednom zdrojovém souboru voláte funkci, k níž máte hlavičku, ale chybí tělo. Anebo je tělo definováno v souboru, který jste zapomněli do překladu zařadit.
- Tuto chybu také dostanete, pokud budete používat externí knihovnu a zapomenete ji přilinkovat (použít hlavičkové soubory nestačí).
- Pokud symboly neznáme a obsahují slova jako dbg, debug apod., může jít o konflikt verze C Runtime knihovny, kterou používá váš projekt a se kterou byly zkompilovány cizí knihovny. Je třeba použít stejné verze.
- Příklad, kde se tento problém vyskytne:
// Tato hlavička funkce bude typicky v includovaném hlavičkovém souboru.
// Říká překladači, že někde je napsaná funkce fn, která vrací int a
// to překladači stačí. Až linker si bude stěžovat, když tato funkce nikde
// nebude.
int fn();
void main() {
fn(); // použijeme funkci, které chybí tělo, to vyhodí unresolved external
}
- ... already defined in error_test.obj
- Jak už chybová hláška napovídá, daný symbol se vyskytuje ve dvou zdrojových souborech a v obou má stejné jméno. Pokud se jedná o funkci, musí mít jedna z nich jiné jméno.
- Pokud se snažíte používat jednu proměnnou z více zdrojových souborů a proto jste ji vložili do hlavičkového souboru, musíte to udělat trochu jinak. Proměnná musí být deklarovaná jen v jednom zdrojovém souboru, v ostatních na ní musí být pouze odkaz. Například pro objekt spravující vstup by to mohlo vypadat takto:
input.cpp:
InputManager inputManager; // toto si můžeme představit jako vytvoření místa v paměti
input.h:
extern InputManager inputManager; // Zde je klíčové slovo extern. Říká, že někde existuje
// proměnná inputManager, ale nevytváří nový symbol.
game.cpp:
#include "input.h"
// a můžeme používat inputManager
- ... redefiniton
- Tato chybová hláška říká, že daný symbol už překladač jednou viděl. To se může stát, když includujete jeden hlavičkový soubor vícekrát. Proto hlavičkové soubory obvykle vypadají takto:
#ifndef INPUT_H_INCLUDED #define INPUT_H_INCLUDED ... obsah souboru #endif
- Tyto instrukce zamezí opakovanému vkládání hlavičkového souboru. Novější překladače podporují jednodušší příkaz
#pragma once
- spousta chyb týkajících se kódu, který není váš
- Pravděpodobně bude problém s pořadím includovaných souborů nebo bude syntaktická chyba někde před includovanáním hlavičkového souboru, ve kterém překladač hlásí chyby.
