2013-03-01 155 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不同)需要在n-1個字符內換行符,EOF或讀取錯誤。因此溢出是一個運行時約束衝突。如果存在運行時約束衝突,則將緩衝區中的第一個字符設置爲空字符,並讀取並丟棄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 

> 

注意我如何期望gets_s刪除第一行輸入的內容。

如果主要問題是線路輸入和線路之間的一個一一對應保存,在調試時重要的是,我們仍然需要寫我們自己的函數(類似的K &的r函數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; 
} 

通過這種功能可以保持一對一的對應關係,緩衝區爲 飽和,並且不存在運行時約束衝突。

我在得出這個結論時是否正確。

回答

3

你試過傳遞`-std = c11'嗎?

根據this pagegets_s在C11中引入。假設你正在使用GCC,你可以使用'-std = c11'選項啓用有限的C11支持。

+0

@Vlad:'gets'完全沒用。這就是C11將其徹底清除的原因。 – 2013-03-01 02:26:13

+3

我剛剛嘗試過'-std = c11';它仍然沒有找到'gets_s'。並且'get_s'和C11附件K的其餘部分「邊界檢查接口」是* optional *,即使完全符合C11的實現(gcc還沒有)。一個實現可以定義宏__STDC_LIB_EXT1__並提供接口 - 或者不。 – 2013-03-01 02:45:54

+0

所以,基本上,使用'fgets'。 – nneonneo 2013-03-01 02:55:29

1

你應該做的第一件事是啓用編譯器警告。例如,將-Wall傳遞給GCC。做到這一點之後,它會發出以下命令:

warning: implicit declaration of function ‘gets_s’ 

這基本上意味着,編譯器不知道gets_s()功能是什麼。那麼它究竟如何編譯呢?在C中,這被稱爲隱式函數聲明,它基本上說,如果沒有函數聲明,編譯器應該假設有一個函數返回一個整數並接受任意數量的參數。例如:

int foo(...); 

因此,編譯器已經爲您快樂地生成了代碼。從你的特定情況下山下。你會發現,如果你使用了一個實際存在的函數(比如標準庫中存在的標準printf()),那麼一切都會很好(幾乎所有的陷阱)。事實上,雖然在C11之前的世界中沒有像gets_s()這樣的東西(如果我沒有弄錯,它只會出現在微軟的C庫中)。因此,鏈接器不能簡單地找到它。這就是爲什麼它放棄嘗試組裝程序,並吐出你得到的錯誤信息。換句話說 - 不要使用gets_s。改爲使用fgets。它幾乎是同一件事 - 唯一的區別是它是標準的,它期望您指定FILE *(爲此您給它stdin)。您可以在終端中輸入man fgets來閱讀這些文檔。或者(因爲手冊頁可能未安裝在您的系統上),您可以在線找到它,here

由於這裏很少有朋友指出,在C11中增加了gets_s()。不幸的是,C11沒有完全在Ubuntu使用的GCC(和glibc)中實現。這項工作正在進行中,您可以在GCC的C11 Status Wiki中查看其狀態。因爲@Keith Thompson和C11附件K「界限檢查界面」的其餘部分所提到的是可選,即使對於完全符合C11的實現(gcc還沒有)來說也是如此。一個實現可能會定義宏__STDC_LIB_EXT1__並提供接口 - 或者不。

所以,基本上,使用fgets

+1

'gets_s'存在並且是真實的。它在C1x中,而不是在C99中。 – nneonneo 2013-03-01 02:25:47

+0

您正在運行哪個實施? – 2013-03-01 04:23:56

+0

@ChrisSzalwinski:gcc 4.7.2與glibc 2.16。但即使在最新版本中,C11也不存在(查看狀態鏈接)。 – 2013-03-01 11:57:20