2017-05-30 123 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) –

相关问题