I “m egy olyan osztályban, amely C-t használ, és az oktatóm sajnos a gets() elemet használta a mintakódban.

Mivel ez nyilvánvalóan szörnyű mulasztás, valószínűleg meghatározatlan viselkedést és egyéb problémákat okoz (csak egy kicsit szarkazmus), úgy döntöttem, hogy megvalósítom gets_s() , mert szórakoztató gyakorlat volt, és néha egyszerűen nem ér teljes hibajelzés a fgets() használatával, és csak váratlanul hosszú sorokat akar csonkítani.

Nem érdekel, hogy ez teljes mértékben megvalósítja-e a gets_s() a C11 szabványban meghatározottak szerint – ez csak állítólag az gets() helyettesítője, amely nem túllépi a puffert.

Azonban az a nagyon fontos, hogy ez a funkció valóban azt tegye, amit hirdet: biztonságban van és nem túllépi a puffert.

Ez az én fi első munka a C-ben (általában a vagy alkalmazást használom), és mindent értékelek tippek, bár szeretnék legalább néhányat említeni ennek a kódnak a biztonságáról, és érdekelne a hordozhatóság is (a jelenlegi fordítók felé).

gets_s.h

#include <stdio.h> #include <string.h> #define GETS_S_OK 0 #define GETS_S_ERROR 1 #define GETS_S_OVERRUN 2 static inline int gets_s( char str[], int n ) { char *str_end, *fgets_return; int temp; fgets_return = fgets( str, n, stdin ); /* If fgets fails, it returns NULL. This includes the case where stdin is exhausted. */ if ( fgets_return == NULL ) { str[0] = "\0"; return GETS_S_ERROR; } str_end = str + strlen(str) - 1; if ( str_end == "\n" ) { *str_end = "\0"; return GETS_S_OK; } temp = fgetc( stdin ); if (temp == EOF || temp = "\n") return GETS_S_OK; do temp = fgetc( stdin ); while ( temp != EOF && temp != "\n" ); return GETS_S_OVERRUN; } 

és egy kis tesztfájl:

gets_s.c

#include "gets_s.h" #include <stdio.h> int main() { char buffer[10]; int gets_s_return; printf("Enter up to %d characters safely.\n", sizeof(buffer) - 1); gets_s_return = gets_s( buffer, sizeof(buffer) ); printf("buffer = %s", buffer); printf("gets_s return = %d", gets_s_return); return 0; } 

Sikeresen fordít a gcc -Wall -Wextra -Wpedantic -Werror gets_s.c alkalmazással, így a “plusz”.

Válasz

Először ne hívjuk gets_s -nek, mivel az aláírás és a viselkedés finom és nem túl finom módon különbözik egymástól, éppen ezért zavartsághoz és csalódottsághoz vezet. Egyébként tényleg nem szeretné a gets_s -szerződést.
Nevezzen valami leírónak, például: getline_truncated.

Tudja, hogy a n <= 0 UB az Ön implementációjában?

if (temp == EOF || temp = "\n") ^ 

Biztos vagyok benne, hogy fordítója figyelmeztet a fenti elgépelésre.
Vagy ne kérjen tőle minden figyelmeztetést (-Wall -Wextra -std=...)?

Javaslom a visszatérési kódok újradefiniálása és átnevezése a jobb eredménytesztelés érdekében:

#define GETS_S_TRUNCATED 1 // Because truncation is not neccessarily an error #define GETS_S_OK 0 #define GETS_S_ERROR EOF // Because we already have an appropriate negative constant 

Így tesztelheted a ==0 vagy >=0 attól függően, hogy mit dönt “sikernek”, illetve !=0 vagy <0 a “kudarcért”.

Megjegyzések

  • A temp = "\n" elírási hiba ebben csak bejegyzés; Eredetileg egy külön gépre írtam a kódot, majd újra begépeltem a kérdéshez. Bizonyára ' biztos voltam benne, hogy része lett volna a kódomnak uld hibáztak (ahogy összeállítottam a -Wall -Wextra -Wpedantic -Werror fájlmal.
  • @ CAD97 Ezért írta sok olyan C programozó, aki értékeli a helyességet és a biztonságot, '\n' == temp – így, ha == gépel = gépelnek, sokkal határozottabb hibát kap

Válasz

  • A kód túl sokat olvashat:

     temp = fgetc( stdin ); if (temp == EOF || temp = "\n") return GETS_S_OK; 

    Ha a temp nem EOF és \n , a karakter elveszett. Jobb lenne ungetc().

  • A kód meghaladja a megbízást. A hurok

     do temp = fgetc( stdin ); while ( temp != EOF && temp != "\n" ); 

    garantálja, hogy a hívó soha nem fog üres karakterláncot látni. Az üres karakterláncok néha szemantikailag értelmesek.

  • man fgets:

    A fgets () és a get () függvények nem tesznek különbséget a fájl vége és a hiba között, és a hívóknak a feof ( 3) és a ferror (3) segítségével meghatározhatja, hogy melyik történt.

    Kiváló helyzetben van éppen ezzel. A vak elválaszolás helyett a GETS_S_ERROR, határozza meg, mi történt, és ennek megfelelően térjen vissza. Pl. #define GETS_S_EOF 3.

Megjegyzések

  • I ' m utánozva gets(), hogy I ' m a sor végéig olvasva, az ötlet az, hogy ' az, amit valaki, aki használta volna akar. Ha meg akarja állítani az n-mínusz-egy karakter viselkedést, használja a fgets() parancsot. Vagy legalábbis ez volt az oka annak, hogy ezt a viselkedést válasszam. (Ha azt akarod mondani, hogy túl sokat olvasok ' m, mondd meg, miért választanád kifejezetten ezt a viselkedést. Úgy döntöttem, hogy folytatom az olvasást, hogy utánozzam a gets() ha nem írta ' t a puffer elé.)
  • @ CAD97 Megértem, hogy kifogása az első felsorolásomra vonatkozik. A kódod valóban utánozza a következőt: gets, és valóban nem ' t túlcsordítja a puffert.Az a véleményem, hogy az gets többféleképpen is meg van törve. getline többé-kevésbé megoldja mindet.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük