2013-03-01 3 views
1

Я использую GCC на Ubuntu 4.6.1 и 4.6.2 SUSE с помощью следующей командыНеопределенная ссылка на gets_s?

gcc gets_s.c 

Мой исходный код

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

} 

Конкретизируя мой вопрос:

принципала проблема для меня - это взаимно однозначное соответствие между строками ввода и сохраненными строками.

При успехе разница между fgets и gets_s заключается в том, что fgets включает терминатор новой строки, в то время как gets_s заменяет терминатор новой строки нулевым терминатором, чтобы поддерживать взаимно однозначное соответствие между вводами строк и успешными вызовами gets_s ,

Для ввода, который переполняет длину буфера, fgets принимает количество символов, которые вписываются в буфер, и оставляет остальные в буфере ввода для следующих fgets.

В стандарте (K.3.5.4.1) указано, что с gets_s (в отличие от gets) требуется строка новой строки, EOF или ошибка чтения в пределах n-1 символов. Следовательно, переполнение является нарушением ограничения времени выполнения. Если есть нарушение ограничения времени выполнения, первый символ в буфере устанавливается на нулевой символ, а символы в буфере ввода stdin считываются и отбрасываются до тех пор, пока не будет прочитан символ новой строки, произойдет конец файла или возникает ошибка чтения.

Соответственно на успех, я ожидал:

>fgets 

First Name : Chris 
Last Name : Szalwinski 
Chris 

Szalwinski 

> 

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

При переполнении, я ожидал другое поведение fgets и gets_s. Другими словами,

>fgets 
First Name : Christopher 
Last Name : Christophe 
r 


> 

>gets_s 
First Name : Christopher 
Last Name : Szalwinski 

Szalwinski 

> 

Обратите внимание, как я ожидал, что get_s полностью удалит содержимое первой строки ввода.

Если основной проблемой является взаимно однозначное соответствие между линиями ввода и линий сохраняются, что очень важно при отладке, нам все еще нужно, чтобы написать свою собственную функцию (по аналогии с K GetLine & R в)

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

С такой функцией поддерживается взаимно однозначное соответствие, буфер насыщен и не существует нарушения ограничения времени выполнения.

Правильно ли я делаю это заключение.

ответ

3

Вы пробовали передать `-std = c11 '?

Согласно this page, gets_s был введен в C11. Предполагая, что вы используете GCC, вы можете включить ограниченную поддержку C11 с помощью опции `-std = c11 '.

+0

@ Vlad: 'get' абсолютно бесполезен. Именно поэтому C11 полностью удаляет его. –

+3

Я просто попробовал сам '-std = c11'; он все еще не находит 'gets_s'. И 'get_s', наряду с остальной частью C11 Annex K« Интерфейсы проверки границ », * необязательно *, даже для полностью соответствующих реализаций C11 (которые gcc еще нет). Реализация может определять макрос '__STDC_LIB_EXT1__' и предоставлять интерфейсы - или нет. –

+0

Итак, в основном, используйте 'fgets'. – nneonneo

1

Первое, что вам нужно сделать, это включить предупреждения компилятора. Например, передайте -Wall в GCC. После того, как это будет сделано, он будет выдавать следующее:

warning: implicit declaration of function ‘gets_s’ 

который в основном означает, что компилятор не имеет представления о том, что gets_s() функции есть. Итак, как же он вообще компилятор?В C это называется объявлением неявной функции, которая в основном говорит, что если нет объявления функции, компилятор должен предположить, что существует функция, которая возвращает целое число и принимает любое количество параметров. Например:

int foo(...); 

Таким образом, компилятор с радостью сгенерировал код для вас. Оттуда идет по склону в вашем конкретном случае. Понимаете, если вы использовали функцию, которая фактически существует (скажем, что-то вроде стандартного printf(), который существует в стандартной библиотеке), тогда все было бы хорошо (почти, есть больше gotchas). На самом деле, хотя в пред-C11-мире нет такой вещи, как gets_s() (если я не ошибаюсь, она появляется только в библиотеке Microsoft C). Поэтому линкер не может просто найти его. Вот почему он отказывается от попытки собрать программу вместе и выплевывает это сообщение об ошибке, которое вы получаете. Другими словами - не используйте gets_s. Вместо этого используйте fgets. Это почти то же самое - единственная разница в том, что она стандартная, и она ожидает, что вы укажете FILE * (для которой вы даете stdin). Вы можете прочитать документацию для них, набрав в своем терминале man fgets. В качестве альтернативы (поскольку в вашей системе не могут быть установлены ручные страницы), вы можете найти ее в Интернете, here.

Как мало друзей здесь указали, gets_s() был добавлен в C11. К сожалению, C11 не полностью реализован в GCC (и glibc), который использует Ubuntu. Это незавершенное производство, и вы можете проверить его статус в GCC C11 Status Wiki.

Как уже упоминалось @Keith Томпсон, наряду с остальной частью C11 Приложения К «Bounds проверки интерфейсов», является опционально, даже для полностью корректные реализации С11 (которые GCC еще не). Реализация может определять макрос __STDC_LIB_EXT1__ и предоставлять интерфейсы - или нет.

Итак, в основном, используйте fgets.

+1

'get_s' существует и является реальной вещью. Он находится в C1x, а не на C99. – nneonneo

+0

Какая реализация выполняется? –

+0

@ChrisSzalwinski: gcc 4.7.2 с glibc 2.16. Но C11 не существует даже в новейших (проверьте ссылку статуса). – 2013-03-01 11:57:20

Смежные вопросы