私はCを使用しているクラスにいて、インストラクターはを持っています残念ながらサンプルコードでgets()を使用しました。

これは明らかに凶悪な見落としであり、未定義の動作やその他のさまざまな問題を引き起こす可能性があります(ほんの少しだけ) sarcasm)、 gets_s() を実装することにしました。これは楽しい演習であり、時には価値がないためです。 fgets()で完全なエラーチェックを実行し、予期しない長い行を切り捨てたいだけです。

これが-これは、バッファをオーバーランしないgets()のドロップイン置換であると想定されています。

ただし、非常に重要なのは、この関数が実際にアドバタイズすることを実行することです。つまり、安全で、バッファをオーバーランしません。

これは私のfiです。初めてCで作業するとき(私は通常またはを使用します)、すべてに感謝しますヒント。ただし、このコードの安全性について少なくともいくつか言及したいと思います。また、(現在のコンパイラへの)移植性にも関心があります。

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

および小さなテストファイル:

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

gcc -Wall -Wextra -Wpedantic -Werror gets_s.cで正常にコンパイルされるため、「saplus。

Answer

まず、署名と動作が微妙な方法とそれほど微妙ではない方法で異なるため、gets_sとは呼ばないでください。混乱と欲求不満につながります。とにかく、本当にgets_s-契約を望まないでしょう。
getline_truncated

n <= 0が実装のUBであることをご存知ですか?

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

コンパイラが上記のタイプミスについて警告していると確信しています。
または、すべての警告を要求しませんか(-Wall -Wextra -std=...)?

お勧めしますより良い結果テストを可能にするために、リターンコードを再定義して名前を変更します:

#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 

この方法で、または>=0は、それぞれ「成功」であると判断した場合に応じて、それぞれ!=0または<0「失敗」の場合。

コメント

  • temp = "\n"はこのタイプミスです。投稿のみ。元々は別のマシンでコードを記述し、質問のために再入力しました。'コードの一部であったと確信しています。 uldでエラーが発生しました(-Wall -Wextra -Wpedantic -Werrorでコンパイルしたため。
  • @ CAD97これが、正確性とセキュリティを重視する多くのCプログラマーが-そのように、===に入力すると、はるかに明確なエラーが発生します

回答

  • コードの読み取りが多すぎる可能性があります:

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

    tempEOFでも\nでもない場合、キャラクターが失われます。 ungetc()それをお勧めします。

  • コードはマンデートを超えています。ループ

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

    呼び出し元に空の文字列が表示されないことを保証します。空の文字列は意味的に意味がある場合があります。

  • man fgets

    fgets()関数とgets()関数はファイルの終わりとエラーを区別しないため、呼び出し元はfeof( 3)とferror(3)を使用して、どちらが発生したかを判別します。

    これを実行するのに最適な位置にあります。盲目的にGETS_S_ERROR、何が起こったかを判断し、それに応じて戻ります。例:#define GETS_S_EOF 3

コメント

  • I 'はgets()を模倣しています'行の最後まで読んでいます。'は、が望んでいます。 stop-at-n-minus-one-characters動作が必要な場合は、fgets()を使用してください。または少なくとも、それがその行動を選んだ私の理由でした。 (私が'を読みすぎていると言いたい場合は、その動作を明示的に選択する理由を説明してください。私はgets()もしそれが'バッファを超えて書き込みをしなかった場合。)
  • @ CAD97あなたの反対意見が私の最初の箇条書きに対処していることを理解しています。あなたのコードは確かにgetsを模倣しており、実際に'はバッファをオーバーフローしません。私のポイントは、getsが複数の方法で壊れているということです。 getline多かれ少なかれそれらすべてを解決します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です