저는 C를 사용하는 수업에 속해 있고 강사는 안타깝게도 샘플 코드에서 gets()를 사용했습니다.

이것은 명백히 끔찍한 감독이므로 정의되지 않은 동작 및 기타 다양한 문제를 일으킬 수 있습니다 (약간 풍자), 저는 gets_s() 를 구현하기로 결정했습니다. 재미있는 운동이었고 때로는 가치가 없었기 때문입니다. fgets()로 전체 오류 검사를 수행하고 예기치 않게 긴 줄을 자르고 싶을뿐입니다.

C11 표준에 지정되어 있습니다. 이것은 버퍼를 오버런하지 않는 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로 성공적으로 컴파일되므로 “더하기

답변

먼저 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.

댓글

  • 나는 ' gets()를 모방하고 있습니다. ' 줄 끝까지 읽고 있습니다. 아이디어는 ' 누군가가 가 원합니다. stop-at-n-minus-one-characters 동작을 원하면 fgets()를 사용하면됩니다. 아니면 적어도 그 행동을 선택한 이유였습니다. (' 너무 많이 읽고 있다고 말하고 싶다면 그 행동을 명시 적으로 선택하는 이유를 말씀해주세요. 저는 계속해서 gets() ' 버퍼를 지나치지 않은 경우.)
  • @ CAD97 귀하의 이의가 제 첫 번째 글 머리 기호를 해결하는 것으로 알고 있습니다. 귀하의 코드는 실제로 gets를 모방하고 실제로 ' 버퍼를 오버플로하지 않습니다.내 요점은 gets가 여러 가지 방식으로 손상되었다는 것입니다. getline는 모두 해결합니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다