GNU/Linux >> Znalost Linux >  >> Linux

Nejlepší postupy kódování pro programování systému Linux v jazyce C – část 1

Při vývoji programu musí mít programátor na paměti několik věcí, například kód by neměl být složitý, tj. měl by být udržovatelný, přenositelnost je další oblastí, kterou je třeba mít na paměti. Vidíme tedy, že existují některé osvědčené postupy, které by měl programátor dodržovat, aby vytvořil dobrý kód. Zde v tomto článku se zaměříme na některé osvědčené postupy, které by měl programátor dodržovat při práci se systémovými voláními v Linuxu.

Co je systémové volání?

Systémové volání je volání speciální funkce, které se provádí za účelem vyžádání nějaké služby z jádra. Požadovanou službou může být vytvoření nového procesu, přístup k hardwaru, jako je pevný disk atd. Při systémovém volání se provádění přepne z uživatelského režimu do režimu jádra a když požadovanou službu poskytuje jádro, pak provedení se přepne zpět do uživatelského režimu. Příklady systémových volání mohou být fork(), read(), write() atd.

Zacházení se systémovými voláními

Při řešení systémových volání byste měli mít na paměti následující body:

  • Programátor by měl mít znalosti o systémovém volání. Například co přesně dělá, používá systémové prostředky, jaký typ argumentů očekává a zvláště v jakých případech selže.
  • Většina systémových volání linuxu vrací chybový kód, pokud selžou. Tyto chybové kódy se mohou lišit v závislosti na typu chyby, která způsobila selhání. Mělo by tedy existovat správné zpracování chyb, aby každý druh chyby byl řádně zpracován a jasně eskalován (buď uživateli nebo nadřazenému modulu).
  • Pro důkladnou znalost systémového volání a chybových kódů, které vrací, bych důrazně doporučil projít manuálovou stránku tohoto konkrétního systémového volání. Manuálové stránky jsou nejlepší reference pro začátek a rozvíjení dobrých základních znalostí o jakémkoli systémovém volání v Linuxu.

Obecné selhání systémového volání

Přestože selhání systémového volání může záviset na typu chyby, ke které došlo při provádění systémového volání, zde je seznam důvodů, které většinou přispívají k selhání systémového volání:

  •  Pokud se systémové volání pokusí o přístup k systémovému hardwaru a z nějakého důvodu není hardware dostupný nebo předpokládáme, že je hardware vadný, pak se systémové volání v takovém případě nezdaří.
  • Pokud se během provádění systémového volání objeví signál s vysokou prioritou, může to také způsobit selhání provedení systémového volání.
  • Jsou situace, kdy se program prostřednictvím systémového volání pokouší provést konkrétní úlohu, která vyžaduje speciální oprávnění nebo oprávnění root. Pokud program takové oprávnění nemá, selže i systémové volání.
  • Předávání neplatných argumentů je dalším velmi častým důvodem selhání systémových volání.
  • Předpokládejme, že je provedeno systémové volání za účelem vyžádání nějaké paměti z haldy a systém z nějakého důvodu není schopen přidělit paměť žádajícímu procesu, který provedl systémové volání, v tomto případě také selže systémové volání.
  • li>

Výše uvedený seznam není vyčerpávající, protože může existovat řada dalších důvodů, kvůli kterým může systémové volání selhat.

Práce s chybovými kódy

Jak již bylo uvedeno, každé systémové volání vrací specifický kód chyby pro každý typ chyby, na kterou narazil (která způsobila selhání systémového volání). Identifikace a sdělení chybových informací je tedy velmi zásadním úkolem programování. Obecně platí, že většina systémových volání vrací '0' při úspěchu a nenulová při neúspěchu, ale ta systémová volání, která vracejí ukazatel na paměť (jako malloc() ), vracejí '0' nebo NULL při selhání a nenulovou hodnotu ukazatele při úspěchu .

POZNÁMKA:Výše ​​uvedené pozorování nemusí platit pro všechna systémová volání. Velmi dobře mohou existovat nějaké výjimky.

Takže, když se vrátíme k chybovým kódům, jak bylo diskutováno, mohou poskytnout zásadní informace o příčině selhání systémového volání. Nyní, protože každý chybový kód je spojen s konkrétním důvodem, takže program může mít mapu chybových kódů a text, který popisuje příčinu chyby. To je však vysoce neefektivní a nepraktické, protože by to znamenalo velké množství mapování pro každé systémové volání používané v programu. Nyní je tedy otázkou, jaký by mohl být efektivnější způsob, jak toho dosáhnout?

Proměnná „errno“

Z manuálové stránky této proměnné:

Hlavičkový soubor  definuje celočíselnou proměnnou errno, která je nastavena systémovými voláními a některými funkcemi knihovny v případě chyby, aby indikovala, co se pokazilo. Jeho hodnota je významná pouze tehdy, když návratová hodnota volání indikovala chybu (tj. -1 u většiny systémových volání; -1 nebo NULL u většiny funkcí knihovny); funkce, která uspěje, může změnit errno.
Platná čísla chyb jsou všechna nenulová; errno není nikdy nastaveno na nulu žádným systémovým voláním nebo funkcí knihovny. Pro některá systémová volání a funkce knihovny (např. getpriority) je -1 platnou návratností úspěchu. V takových případech lze úspěšný návrat odlišit od návratu chyby tak, že před voláním nastavíte errno na nulu, a pokud volání vrátí stav, který naznačuje, že mohlo dojít k chybě, zkontrolujete, zda errno nemá nulová hodnota. errno je standardem ISO C definováno jako modifikovatelná hodnota typu int a nesmí být explicitně deklarována; errno může být makro. errno je místní vlákno; jeho nastavení v jednom vlákně neovlivní jeho hodnotu v žádném jiném vláknu.

Tak. z výše uvedeného popisu je zcela jasné, že je to velmi šikovný nástroj, pokud jde o zpracování chyb systémových volání na Linuxu a může nám ušetřit spoustu tvrdé práce. Dejte si však pozor, abyste tuto proměnnou nepoužili ve vícevláknovém programu, protože je lokální ve vláknu, takže jakákoli změna hodnoty errno v jednom vlákně nemůže být přístupná v žádném jiném vláknu.

Strerror() API

No, jeden problém s použitím pouze errno je ten, že je to stále pouze celočíselná hodnota. Popis je vždy užitečnější při protokolování nebo při předávání příčiny chyby uživateli. Musí tedy existovat mapa chybových kódů a příčiny, ke které se mapují. Zde přichází rozhraní API „strerror()“. Tato funkce bere proměnnou errno jako argument a vrací ukazatel na řetězec, který obsahuje popis příčiny, na kterou je kód chyby mapován.

#include <string.h>
char *strerror(int errnum);

K dispozici jsou i další varianty této funkce. Pro více informací navštivte manuálovou stránku tohoto API.

POZNÁMKA:Zainteresovaní čtenáři mohou také projít rozhraním perror() API. Používá se k vytištění chybové zprávy o selhání systémového volání při standardní chybě.

Příklad

Vezměme si příklad, který demonstruje použití errno a strerror()

#include<stdio.h>
#include<errno.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
    int fd = -1;

    // Always Reset errno before use.
    errno = 0;

    // Make sure you are opening a file that does not exist
    fd = open("abcd",O_RDONLY);
    if(fd == -1)
    {
        // Seems like some error occured. Use strerror to print it
        printf("\nStrerror() says -> [%s]\n",(char*)strerror(errno));
        return 1;
    }
    return 0;
}

V kódu výše:

  • errno je inicializováno na „0“, protože není zaručeno, že bude zpočátku nula.
  • Otevřete neexistující soubor, aby systémové volání open() selhalo.
  • Nyní se k vytištění chybové zprávy na základě kódu errno používá strerror() API.

Když je spuštěn výše uvedený program:

$ ./strerror
Strerror() says -> [No such file or directory]

Vidíme tedy, že ve výstupu vidíme smysluplnou chybovou zprávu namísto chybového kódu.


Linux
  1. 22 nejlepších textových editorů Linux pro programování a kódování

  2. 10 nejlepších IPTV pro systém Linux/Ubuntu v roce 2022

  3. Tabulka systémových volání Linux nebo cheatsheet pro shromáždění

  1. Linux Server Hardening – osvědčené postupy

  2. Vyberte si nejlepší souborový systém pro váš Linux

  3. 6 nejlepších linuxových distribucí pro programování

  1. Nejlepší linuxové distribuce pro hraní her (část 2)

  2. Jak nainstalovat R Programming Language Tools na Linux Mint 20

  3. 10 nejlepších prohlížečů komiksů pro systém Linux