C gets_s() implementation I'm in a class that is using C, and my instructor has unfortunately used gets() in sample code.

As this is obviously a heinous oversight, likely to cause undefined behavior and other various issues (only a little sarcasm), I decided to implement gets_s(), because it was a fun exercise and sometimes it's just not worth it to do full error checking with fgets() and you just want to truncate unexpectedly long lines.

I'm not concerned whether this fully implements gets_s() as specified in the C11 standard -- this is just supposed to be a drop-in replacement for gets() that doesn't overrun your buffer.

However, what is very important is that this function actually does what it advertises: it's safe and doesn't overrun the buffer.

This is my first time working in C (I usually use java or kotlin), and I appreciate all tips, though I'd like at least some mention of the safety of this code, and am also interested in portability (to current compilers).

gets_s.h

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#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 &amp;&amp; temp != '\n' );

  return GETS_S_OVERRUN;
}


and a small test file:

gets_s.c

#include "gets_s.h"
#include &lt;stdio.h&gt;

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


It compiles successfully with gcc -Wall -Wextra -Wpedantic -Werror gets_s.c, so that's a plus.
First, don't call it gets_s as the signature and behavior differs in some subtle and not-so-subtle ways, that just leads to confusion and frustration. Anyway, you really wouldn't want the gets_s-contract.
Call it something descriptive like getline_truncated.

Do you know that n &lt;= 0 is UB in your implementation?

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


I'm sure your compiler warns you about the typo above.
Or don't you ask it for all warnings (-Wall -Wextra -std=...)?

I suggest re-defining and re-naming your return-codes to allow better result-testing:

#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


This way you can test for ==0 or &gt;=0 depending on what you decide is "success", respectively !=0 or &lt;0 for "failure".