C/C++ (29) - Standardní knihovna počtvrté
Dnes v rychlosti probereme locale a zpracování jednotlivých znaků, v druhé části článku dojde na standardní i nestandardní ukončování programu.
15.12.2005 06:00 |
Jan Němec
| Články autora
| přečteno 23044×
Národní prostředí
Jazyk C pochází ze 70. let a je to na něm vidět. Před 35 lety jen málo
lidí od počítačů napadlo, že by někdo mohl chtít používat jinou znakovou sadu,
formát čísel, data a podobně, než používají Američané. Později byla do C jakási
podpora národního prostředí doplněna, ale na některých překladačích dosud
nefunguje nebo funguje jen částečně (což ale není problém gcc), takže pro
použití v přenositelném kódu je jen obtížně použitelná. Standardní knihovna
podporuje pouze terminálový
vstup a výstup, přičemž řetězce jsou jen pole bytů, která se na výstup
posílají v podobě binárně shodné se zápisem ve zdrojovém kódu. Lokalizace
tak má jen omezené pole působnosti, neboť neřeší například problematiku
fontů nebo překódování do a z unikódu. Troufl bych si proto tvrdit, že
lokalizaci programu na úrovni standardní knihovny C je lepší se vyhnout.
#include <stdio.h>
#include <locale.h>
int main(void) {
printf("%f\n", 1.45);
setlocale(LC_ALL, "");
printf("%f\n", 1.45);
return 0;
}
Na počátku programu je podle normy nastavené přenositelné "C" prostředí.
Funkce printf proto vypíše číslovku s desetinnou tečkou. Volání setlocale
změní charakter prostředí ve všech (LC_ALL) oblastech
(znaková sada, výpis čísel, ...) na výchozí (parametr "") na daném počítači.
Na mém česky nainstalovaném Mandriva Linuxu 2006 s gcc 4.0.1 a glibc 2.3.5
uvedený program oddělí při druhém volání printf desetinná místa čárkou.
Na českých Windows 98 s MS Visual C++ 6.0 se uvedený program choval stejně, ale
níže uvedený převod národních znaků na velká písmena pomocí toupper mi fungoval
pouze s gcc na Linuxu.
Lokalizace prostředí na úrovni standardní knihovny je poměrně nebezpečná
záležitost. Uživatel možná rád uvidí desetinou čárku místo tečky (toho
ovšem lze snadno docílit i bez speciální podpory standardní knihovny),
ale pokud jiná část programu například pomocí printf generuje SQL dotazy,
kde musí být oddělovačem tečka, je problém na světě. Proto, pokud programátor
potřebuje nastavovat locale, je vhodné místo všech oblastí (LC_ALL) použít
pouze tu, kde je to nezbytné, například LC_NUMERIC, LC_CTYPE, LC_MESSAGES a
podobně. Zájemce, které se mi nepodařilo odradit, odkazuji na manuálovou
stránku setlocale.
Práce se znaky
Hlavičkový soubor ctype.h obsahuje řadu funkcí a maker pro detekci typu
znaku a konverzi mezi malými a velkými písmeny. Hodit by se mohly zejména
tyto rutiny s dostatečně výmluvnými názvy:
int islapha(int c); /* Je znak písmeno? */
int isdigit(int c); /* Je znak číslice? */
int isalnum(int c); /* Je znak písmeno nebo číslice? */
int islower(int c); /* Je znak malé písmeno? */
int isupper(int c); /* Je znak velké písmeno? */
int isprint(int c); /* Je znak tisknutelný? */
int isspace(int c); /* Jde o "bílý" znak? (mezera, tab, ...) */
int tolower(int c); /* Velká písmena na malá, ostatní znaky nechat. */
int toupper(int c); /* Malá písmena na velká, ostatní znaky nechat. */
Co vlastně je nebo není písmeno závisí na znakové sadě a tím pádem i na
locale. Ve výchozím nastavení "C" se za písmena považují pouze znaky anglické
abecedy. Při nastavení českého locale, budou rutiny fungovat i pro znaky
s diakritikou, ale jen s kvalitním překladačem/libc a jen pokud používáte
stejnou znakovou sadu, kterou považuje překladač/libc za výchozí pro
zvolené locale.
#include <ctype.h>
...
char *pc;
int silne = 0;
pc = heslo;
while (*pc) {
if (isdigit(*pc)) {
silne = 1;
break;
}
}
if (!silne) {
puts("Slabé heslo, neobsahuje ani jednu číslici!");
}
Ukončení programu
Zatím jsme vždy ukončovali chod programu pomocí return ve funkci main.
V některých případech může být tento postup nešikovný, běžným případem jsou
rekurzivní nebo jiná vnořená volání funkcí, kdy program zjistí, že by se měl
ukončit v nejvnitřnějším volání a je příliš komplikované zajistit návrat
ze všech instancí všech funkcí. Dalším případem je ukončení programu
programátorem knihovny, který nemůže ovlivnit volající kód. Standardní
knihovna proto nabízí funkce abort, exit a atexit.
#include <stdlib.h>
void abort(void);
void exit(int status);
int atexit(void (*function)(void));
Funkce abort zajistí okamžité chybové ukončení programu, na linuxu signálem
SIGABRT. Buffery všech otevřených souborů by měly být zapsány a soubory
uzavřeny, ale programátor by na to pochopitelně neměl spoléhat. Funkce je
určena především pro nestandardní ukončení programu při ladění, případně
po nějaké velmi vážné chybě programu, kdy už nemá smysl snažit se cokoli
zachránit a kdy je záměrem uživatele informovat následující hláškou:
[honza@localhost ~]$ ./abort
Neúspěšně ukončen (SIGABRT)
[honza@localhost ~]$
Ukončení programu mimo main nemusí vždy znamenat chybu, případně chyba není
tak vážná, aby bylo nutné program ukončovat nestandardním způsobem. V tom
případě použijeme funkci exit. Její volání (včetně parametru) odpovídá
return ve funkci main. Jedná-li se o řádné ukončení programu, voláme exit(0),
v opačném případě s nějakou nenulovou hodnotou nebo lépe exit(EXIT_SUCCESS)
a exit(EXIT_FAILURE).
Občas se hodí provést na konci programu nějakou akci bez ohledu na to, zda
byl programu ukončen returnem v main nebo funkcí exit. Není jednoduché
toho dosáhnout, neboť program může být ukončen i z knihovny, kterou nemá
programátor pod kontrolou. Naštěstí existuje funkce atexit, která zaregistruje
uživatelskou funkci, jež bude runtimem zavolaná v době ukončení programu.
Je-li funkcí více, volají se v opačném pořadí, než byly zaregistrovány.
#include <stdio.h>
#include <stdlib.h>
void po_main(void) {
puts("po_main");
}
void nakonec(void) {
puts("nakonec");
}
int main(void) {
puts("main - začátek");
puts("registruji nakonec");
atexit(nakonec);
puts("registruji po_main");
atexit(po_main);
puts("main - konec pomocí exit");
exit(EXIT_SUCCESS); /* Jen test funkce exit, return by to zvládnul stejně. */
puts("Sem bych se neměl dostat...");
return 0;
}
Ladění s pomocí assert
Při vývoji větších projektů je třeba počítat s chybami. Nejobtížněji se hledají
chyby typu přepsání paměti za polem nebo přístupu na neinicializovaný ukazatel,
neboť se projevují jen někdy a často až dodatečně a daleko od místa chyby.
Do programu se proto běžně přidává kód, který se snaží chyby odhalit již
v místě jejich vzniku a zpravidla jen vypíše chybovou hlášku a ukončí program.
Podobný kód však může zbytečně zdržovat již odladěný program a navíc
v distribuční verzi (zejména komerčního software) může být někdy přiznání chyby
a násilné ukončení programu větší zlo než
chyba sama o sobě. Již víme, že s pomocí makra preprocesoru a podmíněného
překladu můžeme vyvolávat ladící testy jen ve vývojové verzi programu.
Standardní knihovna se nám to snaží zjednodušit a nabízí rutinu assert.
#include <assert.h>
int main(void) {
int pole[10];
int i;
for (i = 0; i <= 10; i++) {
assert(i < sizeof(pole) / sizeof(int));
pole[i] = 0;
}
return 0;
}
V příkladu se snažím vynulovat pole, ale dopustil jsem se známé chyby "+1",
kdy přistupuji o jeden prvek za konec pole. Chování programu v tomto případě
není definované, záleží na tom, co se nachází za polem. Naštěstí jsem vložil
do cyklu ladící test assert, který v případě nesplnění podmínky ukončí
program pomocí funkce abort a vypíše chybovou hlášku:
assert: assert.c:10: main: Assertion `i < sizeof(pole) / sizeof(int)' failed.
Ladící testy můžeme snadno vypnout, pokud definujeme makro NDEBUG. Rozhodující
je přitom místo (posledního) inkludu hlavičkového souboru assert.h,
#define NDEBUG tedy musí předcházet #include <assert.h>.
Nejlepší je ovšem definice pomocí parametru překladače:
gcc assert.c -o assert -DNDEBUG
Uvedený příklad je trochu vykonstruovaný. Programátor, který správně testuje
meze polí přímo v cyklu pravděpodobně neudělá chybu v ukončovací podmínce
toho samého cyklu. V praxi se spíše setkáme s testováním parametrů funkcí,
užitečné je to zejména pokud jeden programátor napíše knihovnu poskytující
sadu funkcí (jejichž parametrem například nesmí být NULL) a jiný programátor
tuto knihovnu používá.
Pokračování příště
Standardní knihovnu jsme již probrali. V příštím dílu se zamyslíme nad tím,
co ve standardní knihovně nejvíce chybí. Vydalo by to na několik dalších
samostatných seriálů, proto vždy uvedu jen stručný popis a především odkaz
na web, který se problematice věnuje. Ze základní syntaxe jazyka C nám chybí
výčtový typ, i na něj dojde v příštím dílu.
Verze pro tisk
|
Nejsou žádné diskuzní příspěvky u dané položky.
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|