簡體   English   中英

為什么在 GCC (9.3.0) 中仍然沒有實現`gets_s()`?

[英]Why `gets_s()` still isn't implemented in GCC (9.3.0)?

我知道fgets()是字符串輸入更常見和廣泛的選項,但 C11 已經存在了 9 年。 為什么gets_s()仍然無法工作?

即使我添加-std=c11 ,它仍然不起作用,即使gets_s()應該在stdio.h中。

因為它是可選的。 gcc背后的人似乎認為包含它是一個壞主意。 我不知道他們是如何推理的,但可以在 C 標准中找到提示:

推薦做法

fgets function 允許正確編寫的程序安全地處理輸入行太長而無法存儲在結果數組中。 一般來說,這要求 fgets 的調用者注意結果數組中是否存在換行符。 考慮使用 fgets(以及任何需要的基於換行符的處理)而不是 gets_s。

https://port70.net/~nsz/c/c11/n1570.html#K.3.5.4.1

如果要使用gets_s ,請使用另一個編譯器。 或者編寫自己的包裝器,但不要將其命名為gets_s ,因為要使其與規范完全相同是非常棘手的。

C 標准是這樣說的:

運行時約束

s不應是 null 指針。 n既不能等於 0,也不能大於RSIZE_MAX 在從標准輸入讀取n-1字符時應發生換行符、文件結束符或讀取錯誤。

如果存在運行時約束違規,則將 s[0] 設置為 null 字符,並從標准輸入讀取並丟棄字符,直到讀取換行符、文件結束或發生讀取錯誤。

描述

gets_s function 從 stdin 指向的 stream 中讀取最多比n指定的字符數少一個,到s指向的數組中。 在換行符(被丟棄)或文件結尾之后不會讀取其他字符。 丟棄的換行符不計入讀取的字符數。 在讀入數組的最后一個字符之后立即寫入 null 字符。

如果遇到文件結尾並且沒有字符被讀入數組,或者如果在操作過程中發生讀取錯誤,則將s[0]設置為 null 字符,並且 s 的其他元素采用未指定的值。

這里有一件事根本沒有意義。 運行時約束是s不應該是 null 指針。 如果違反運行時約束, s[0]應設置為零。 但是如果s是 null 指針,則操作s[0] = '\0'具有未定義的行為。

這是我嘗試實施它的看法,但 IMO 的規格一團糟,我不相信這一點。 把它做好是很棘手的。

char *my_gets_s(char *s, size_t n)
{
    if(!s) return NULL;

    size_t i=0;
    int ch;

    for(i=0; i<n-1; i++) {
        ch = fgetc(stdin);

        // If end-of-file is encountered and no characters have been read into the array,                          
        // or if a read error occurs during the operation, then s[0] is set to the null character                  
        if(ferror(stdin) || (ch == EOF && i == 0)) {
            s[0] = '\0';
            return NULL;
        }

        // If EOF and we have read at least one character                                                          
        if(ch == EOF) {
            s[0] = '\0';
            return s;
        }

        s[i] = ch;

        if(ch == '\n') {
            s[i] = '\0';
            return s;
        }
    }

    while ((ch = getchar()) != '\n' && ch != EOF);
    s[0] = '\0';
    return NULL;
}

正如其他人所指出的, gets_s()是:

  1. 可選的(許多編譯器實際上並沒有實現它)
  2. 從 C11 開始(所以以前的標准肯定沒有)

如果你真的需要一些東西而不是fgets() ,那么你可以自己實現包裝器,例如:

char* myGets(char* str, int count)
{
    if (fgets(str, count, stdin)) {
        for (int i = 0; i < count; ++i) {
            if (str[i] == '\n') {
                str[i] = '\0';
                break;
            }
        }
        return str;
    } else {
        return NULL;
    }
}

雖然有一個fgets()的替代方法會很有用,它總是讀取整行,如果需要,丟棄多余的信息,並報告讀取了多少字符, gets_s不是這樣的 function。 gets_s function 僅適用於應完全丟棄任何超長輸入行的情況。 執行基於行的 I/O 的唯一好方法是基於fgetc()getchar()構建自己的行輸入例程,使用fgets()與基於字符的 get 一樣大的極端情況邏輯-line 例程,或者 - 如果想要最大化性能並且 stream 不必與其他任何東西共享 - 使用fread()memchr() ,在調用 get 之間將讀取數據保存在私有緩沖區中 -線例程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM