Ich bin in einer Klasse, die C verwendet, und mein Lehrer hat Leider hat gets() im Beispielcode verwendet.

Da dies offensichtlich ein abscheuliches Versehen ist, kann es zu undefiniertem Verhalten und anderen verschiedenen Problemen kommen (nur ein wenig) Sarkasmus), entschied ich mich, gets_s() zu implementieren, weil es eine lustige Übung war und manchmal einfach nicht wert ist Um eine vollständige Fehlerprüfung mit fgets() durchzuführen, möchten Sie nur unerwartet lange Zeilen abschneiden.

Ich bin nicht besorgt, ob dies wie im C11-Standard angegeben – dies soll nur ein Ersatz für gets() sein, der Ihren Puffer nicht überläuft.

Was jedoch sehr wichtig ist, ist, dass diese Funktion tatsächlich das tut, was sie ankündigt: Sie ist sicher und überläuft den Puffer nicht.

Dies ist meine Fi Zum ersten Mal in C arbeiten (ich verwende normalerweise oder ), und ich schätze alles Tipps, obwohl ich zumindest die Sicherheit dieses Codes erwähnen möchte und mich auch für die Portabilität (für aktuelle Compiler) interessiere.

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; } 

und eine kleine Testdatei:

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; } 

Es wird erfolgreich mit gcc -Wall -Wextra -Wpedantic -Werror gets_s.c kompiliert, so dass „sa plus.

Antwort

Nennen Sie es zunächst nicht gets_s, da sich die Signatur und das Verhalten auf subtile und weniger subtile Weise unterscheiden führt zu Verwirrung und Frustration. Wie auch immer, Sie möchten wirklich nicht, dass der gets_s -Vertrag.
Nennen Sie ihn etwas Beschreibendes wie getline_truncated.

Wissen Sie, dass n <= 0 UB in Ihrer Implementierung ist?

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

Ich bin sicher, Ihr Compiler warnt Sie vor dem obigen Tippfehler.
Oder fragen Sie nicht nach allen Warnungen (-Wall -Wextra -std=...)?

Ich schlage vor Definieren und benennen Sie Ihre Rückkehrcodes neu, um bessere Ergebnistests zu ermöglichen:

#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 

Auf diese Weise können Sie auf oder >=0, je nachdem, was Sie als „Erfolg“ bezeichnen, !=0 oder <0 für „Fehler“.

Kommentare

  • Die temp = "\n" ist ein Tippfehler Ich habe den Code ursprünglich auf einem separaten Computer geschrieben und ihn dann für die Frage erneut eingegeben. ' Ich bin mir sicher, dass er Teil meines Codes war Ich hätte mich geirrt (wie ich mit -Wall -Wextra -Wpedantic -Werror kompiliert habe.
  • @ CAD97 Aus diesem Grund hätten viele C-Programmierer, die Wert auf Korrektheit und Sicherheit legen, – Wenn sie auf diese Weise == bis = tippen, erhalten Sie einen viel eindeutigeren Fehler

Antwort

  • Der Code lautet möglicherweise zu viel:

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

    Wenn temp weder EOF noch \n ist ist der Charakter verloren. Sie sollten es besser ungetc().

  • Der Code überschreitet das Mandat. Die Schleife

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

    garantiert, dass der Aufrufer niemals eine leere Zeichenfolge sieht. Manchmal sind leere Zeichenfolgen semantisch bedeutsam.

  • man fgets:

    Die Funktionen fgets () und gets () unterscheiden nicht zwischen Dateiende und Fehler, und Aufrufer müssen feof ( 3) und Fehler (3), um festzustellen, was aufgetreten ist.

    Sie sind in einer hervorragenden Position, um genau das zu tun. Anstatt blind GETS_S_ERROR, bestimmen Sie, was passiert ist, und kehren Sie entsprechend zurück. ZB #define GETS_S_EOF 3.

Kommentare

  • Ich ' ahme gets() nach, indem ich ' Ich lese bis zum Ende der Zeile. Die Idee ist, dass ' jemand ist, der will. Wenn Sie das Stop-at-n-minus-one-Zeichen-Verhalten wünschen, verwenden Sie einfach fgets(). Zumindest war das mein Grund, dieses Verhalten zu wählen. (Wenn Sie sagen möchten, dass ich ' zu viel lese, sagen Sie, warum Sie dieses Verhalten explizit auswählen würden. Ich habe mich entschieden, weiterzulesen, um gets() wenn es nicht ' nicht über Ihren Puffer hinaus geschrieben hat.)
  • @ CAD97 Ich verstehe, dass Ihr Einwand meinen ersten Aufzählungspunkt betrifft. Ihr Code ahmt tatsächlich gets nach, und ' überläuft den Puffer tatsächlich nicht.Mein Punkt ist, dass gets in mehr als einer Hinsicht fehlerhaft ist. getline löst sie mehr oder weniger alle.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.