2

I'm using gcc on Ubuntu 4.6.1 and SUSE 4.6.2 with the following command

gcc gets_s.c

My source code is

// Read and Display Lines
// gets_s.c

#include <stdio.h>

int main(void)
{

    char first_name[11]; 
    char last_name[11]; 

    printf("First Name : ");
    gets_s(first_name, 11);
    printf("Last Name  : ");
    gets_s(last_name, 11);
    puts(first_name);
    puts(last_name);

    return 0;

}

Elaborating on my question:

The principal issue for me is one-to-one correspondence between lines input and lines saved.

On success, the difference between fgets and gets_s is that fgets includes the newline terminator while gets_s replaces the newline terminator with the null terminator so as to maintain a one-to-one correspondence between the lines input and successful calls to gets_s.

For input that overflows the buffer length, fgets accepts the number of characters that fit into the buffer and leaves the rest in the input buffer for the next fgets.

The standard (K.3.5.4.1) states that with gets_s (unlike gets) requires a newline, EOF or read error within n-1 characters. Hence overflow is a runtime-constraint violation. If there is a runtime-constraint violation, the first character in the buffer is set to the null character, and the characters in the stdin input buffer are read and discarded until the new-line character is read, an end-of-file occurs or a read error occurs.

Accordingly on success, I expected:

>fgets

First Name : Chris
Last Name  : Szalwinski
Chris

Szalwinski

>

>gets_s
First Name : Chris
Last Name  : Szalwinski
Chris
Szalwinski
>

On overflow, I expected different behavior from fgets and gets_s. In other words,

>fgets
First Name : Christopher
Last Name  : Christophe
r


>

>gets_s
First Name : Christopher
Last Name  : Szalwinski

Szalwinski

>

Note how I expected gets_s to remove the contents of the first line of input altogether.

If the principal issue is one-to-one correspondence between lines input and lines saved, which is important in debugging, we still need to write our own function (similar to K&R's getline)

char *gets_s(char *s, int n) 
{
    int i, c;
    for (i = 0; i < n - 1 && (c = getchar()) != EOF && c != (int)'\n'; i++)
        s[i] = c;
    s[i] = '\0';
    while (n > 1 && c != EOF && c != (int)'\n')
        c = getchar();
    return c != EOF ? s : NULL;
}

With such a function the one-to-one correspondence is maintained, the buffer is saturated and there is no runtime-constraint violation.

Am I correct in drawing this conclusion.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118

2 Answers2

3

Have you tried passing `-std=c11'?

According to this page, gets_s was introduced in C11. Assuming you're using GCC, you can enable limited C11 support using the `-std=c11' option.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • @Vlad: `gets` is totally useless. Which is why C11 completely removes it. – Billy ONeal Mar 01 '13 at 02:26
  • 3
    I just tried `-std=c11` myself; it still doesn't find `gets_s`. And `get_s`, along with the rest of C11 Annex K "Bounds-checking interfaces", is *optional*, even for fully conforming C11 implementations (which gcc isn't yet). An implementation may define the macro `__STDC_LIB_EXT1__` and provide the interfaces -- or not. – Keith Thompson Mar 01 '13 at 02:45
  • So, basically, use `fgets`. – nneonneo Mar 01 '13 at 02:55
  • fgets() stops at the maximum number of characters without erasing the rest of the line if it does not reach the newline character. gets_s() fails if it does not reach the newline character. Does this mean that I need to write my own version until gets_s() is more widely implemented. – Chris Szalwinski Mar 01 '13 at 04:20
  • @Keith: That's because they made most everything in C11 optional. For instance, VLAs were required in C99, but are optional in C11. – Billy ONeal Mar 01 '13 at 18:10
2

The first thing you should do is enable compiler warnings. For example, pass -Wall to GCC. After that is done, it will issue the following:

warning: implicit declaration of function ‘gets_s’

Which basically means that compiler has no idea what gets_s() function is. So how on earth it compiler in the first place? In C this is called an implicit function declaration, which basically says that if there is no declaration of a function, compiler should assume that there is a function that returns an integer and accepts any number of parameters. For example:

int foo(...);

So the compiler has happily generated the code for you. From there is goes down the hill in your particular case. You see, if you have used a function that actually exists (say, something like a standard printf() that does exist in the standard library) then everything would have been nice (almost, there are more gotchas). In reality though there is no such thing as gets_s() in pre-C11 world (if I am not mistaken, it only appears in the Microsoft's C library). Therefore, the linker cannot simply find it. That is why it gives up trying to assemble the program together and spits out that error message you get. In other words — do not use gets_s. Use fgets instead. It is almost the same thing — the only difference is that it is standard and it expects you to specify the FILE * (for which you give it stdin). You can read a documentation for those by typing man fgets in your terminal. Alternatively (as manual pages might not be installed on your system), you can find it online, here.

As few friends here have pointed out, gets_s() was added in C11. Unfortunately, C11 is not fully implemented in GCC (and glibc) that Ubuntu is using. This is work in progress and you can check its status in GCC's C11 Status Wiki.

As @Keith Thompson mentioned, along with the rest of C11 Annex K "Bounds-checking interfaces", is optional, even for fully conforming C11 implementations (which gcc isn't yet). An implementation may define the macro __STDC_LIB_EXT1__ and provide the interfaces — or not.

So, basically, use fgets.

user13500
  • 3,817
  • 2
  • 26
  • 33