2017-05-30 134 views
1

我正在嘗試編寫一本書Beginning C 5th Ed的示例程序。通過Ivor Horton。試圖編譯它在OSX,我正從GCC以下的輸出:體系結構x86_64的未定義符號:「_gets_s」

$ gcc program6_07.c 
program6_07.c:18:59: warning: format specifies type 'int' but the argument has 
     type 'size_t' (aka 'unsigned long') [-Wformat] 
      "Terminate input by entering an empty line:\n", str_len); 
                  ^~~~~~~ 
program6_07.c:23:5: warning: implicit declaration of function 'gets_s' is 
     invalid in C99 [-Wimplicit-function-declaration] 
    gets_s(buf, buf_len);         // Read a lin... 
    ^
program6_07.c:24:9: warning: implicit declaration of function 'strnlen_s' is 
     invalid in C99 [-Wimplicit-function-declaration] 
    if(!strnlen_s(buf, buf_len))       // Empty lin... 
     ^
program6_07.c:27:8: warning: implicit declaration of function 'strcat_s' is 
     invalid in C99 [-Wimplicit-function-declaration] 
    if(strcat_s(str, str_len, buf))      // Concatenat... 
    ^
program6_07.c:33:60: warning: data argument not used by format string 
     [-Wformat-extra-args] 
    printf("The words in the prose that you entered are:\n", str); 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
program6_07.c:37:18: warning: implicit declaration of function 'strtok_s' is 
     invalid in C99 [-Wimplicit-function-declaration] 
    char * pWord = strtok_s(str, &str_len, delimiters, &ptr); // Find 1st word 
       ^
program6_07.c:37:10: warning: incompatible integer to pointer conversion 
     initializing 'char *' with an expression of type 'int' [-Wint-conversion] 
    char * pWord = strtok_s(str, &str_len, delimiters, &ptr); // Find 1st word 
     ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
program6_07.c:45:13: warning: incompatible integer to pointer conversion 
     assigning to 'char *' from 'int' [-Wint-conversion] 
     pWord = strtok_s(NULL, &str_len, delimiters, &ptr); // Find sub... 
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
8 warnings generated. 
Undefined symbols for architecture x86_64: 
    "_gets_s", referenced from: 
     _main in program6_07-4a1c4c.o 
    "_strcat_s", referenced from: 
     _main in program6_07-4a1c4c.o 
    "_strnlen_s", referenced from: 
     _main in program6_07-4a1c4c.o 
    "_strtok_s", referenced from: 
     _main in program6_07-4a1c4c.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

程序的代碼如下:

// Program 6.7 Find all the words 
#define __STDC_WANT_LIB_EXT1__ 1       // Make optional versions of functions available 
#include <stdio.h> 
#include <string.h> 
#include <stdbool.h> 

int main(void) 
{ 
    char delimiters[] = " \".,;:!?)(";      // Prose delimiters 
    char buf[100];           // Buffer for a line of keyboard input 
    char str[1000];           // Stores the prose to be tokenized 
    char* ptr = NULL;          // Pointer used by strtok_s() 
    str[0] = '\0';           // Set 1st character to null 

    size_t str_len = sizeof(str); 
    size_t buf_len = sizeof(buf); 
    printf("Enter some prose that is less than %d characters.\n" 
      "Terminate input by entering an empty line:\n", str_len); 

    // Read multiple lines of prose from the keyboard 
    while(true) 
    { 
    gets_s(buf, buf_len);         // Read a line of input 
    if(!strnlen_s(buf, buf_len))       // Empty line ends input 
     break; 

    if(strcat_s(str, str_len, buf))      // Concatenate the line with str 
    { 
     printf("Maximum permitted input length exceeded."); 
     return 1; 
    } 
    } 
    printf("The words in the prose that you entered are:\n", str); 

    // Find and list all the words in the prose 
    unsigned int word_count = 0; 
    char * pWord = strtok_s(str, &str_len, delimiters, &ptr); // Find 1st word 
    if(pWord) 
    { 
    do 
    { 
     printf("%-18s", pWord); 
     if(++word_count % 5 == 0) 
     printf("\n"); 
     pWord = strtok_s(NULL, &str_len, delimiters, &ptr); // Find subsequent words 
    }while(pWord);           // NULL ends tokenizing 
    printf("\n%u words found.\n", word_count); 
    } 
    else 
    printf("No words found.\n"); 

    return 0; 
} 

我原以爲我已經定義的可選功能,但我猜我沒有?這只是一本過時的書或一個不好的例子,或者當我試圖編譯它時,我做錯了什麼?

回答

7

gets_s()函數在ISO/IEC 9899:2011(現行C標準)和TR 24731-1的附錄K中定義。這是可選的。它沒有得到廣泛的實施 - 事實上,它基本上只在使用Microsoft C庫的Microsoft系統上可用。類似的評論適用於其他_s函數 - 它們在附件K中定義,除了在微軟的編譯器下,通常不會被實現。

請注意,您可以通過測試編譯器是否設置__STDC_LIB_EXT1__來測試實現中是否可以使用附錄K函數。爲符合附件K的規定,其值應爲200509L以符合原始TR 24731-1或201112L。如果該值由實現定義,則代碼應定義__STDC_WANT_LIB_EXT1__以公開附件K函數的定義。

您將需要使用不同的功能:

  • 對於gets_s(),標準fgets()可能是最接近,但它包含在其中gets_s()不輸入結束的換行符。另外,gets_s()會在出現錯誤時截斷輸出字符串 - 如果在沒有剩餘空間之前沒有換行符,如果發生這種情況,它也會讀到下一個換行符。這些函數都不會執行任何操作。
  • 對於strnlen_s(),請使用strnlen(),可在macOS Sierra(以及Mac OS X)和Linux上使用。
  • 對於strcat_s(),可能使用strlcat(),同樣可在macOS Sierra和Linux上使用。
  • 對於strtok_s(),可能使用strtok_r(),這是POSIX的標準部分。請注意,strtok_r()的接口與strtok_s()的接口不同,但功能基本相同。
+2

而'__STDC_WANT_LIB_EXT1__'也是在C11中引入的嗎? –

+3

@KeineLust:嚴格來說,它是由TR 24731-1技術報告引入的,但就標準而言,是的,它被添加到C11中。但是,您還必須檢查實現中是否定義了__STDC_LIB_EXT1__,以確定是否添加'__STDC_WANT_LIB_EXT1__'會產生任何影響。我不知道提供這個標準的Unix實現。另請參見[您是否使用TR 24731'安全'功能?](https://stackoverflow.com/questions/372980/do-you-use-the-tr-24731-safe-functions) –

相關問題