Windows环境下getline在C语言中实现

jdzmm42g  于 2022-11-30  发布在  Windows
关注(0)|答案(1)|浏览(437)

语句

  • 我知道在Linux/Unix操作系统上有一个叫做getline()的函数。
  • 我想知道还有哪些功能是Windows操作系统中没有的,但在Linux/Unix操作系统中有。

问题

1.有没有自己做的getline()函数可以代替Windows中的那个?
1.有哪些资源可供参考和阅读?

size_t getline(char **lineptr, size_t *n, FILE *stream)
hyrbngr7

hyrbngr71#

相关标准是IEEE Std 1003.1, also called POSIX.1,特别是其系统接口,以及受影响的函数here列表。
我推荐Linux man pages online。不要被它的名字吓住,因为C函数(在第2、3节中描述)有一个部分 Conforming to,它指定了哪些标准对该特性进行标准化。如果是C89、C99等,则它包含在C标准中;如果是POSIX.1,则为POSIX;如果是SuS,则在POSIX之前的单一Unix规范中;如果是4.3BSD,则在旧BSD版本4.3中;如果是SVr 4,则在Unix System V版本4中,依此类推。
Windows实现了自己的C扩展,并避免支持任何POSIX或SuS,但移植了4.3BSD的一些细节。请使用Microsoft文档来查找。
在Linux中,如果在执行#include语句之前定义了某些预处理器宏,C库就会公开这些特性。这些在man 7 feature_test_macros中有描述。我通常在POSIX中使用#define _POSIX_C_SOURCE 200809L,偶尔在GNU C扩展中使用#define _GNU_SOURCE
getline()是一个很好的接口,除了习惯于Microsoft/Windows的程序员使用时,它并不“泄漏”,比如在没有Microsoft专用扩展的情况下,无法将宽字符输出到控制台(因为他们显然不想将该实现放在fwide()中)。
最常见的使用模式是初始化未分配的缓冲区和合适的行长度变量:

char   *line_buf = NULL;
    size_t  line_max = 0;
    ssize_t line_len;

然后,当你读一行时,C库可以自由地重新分配缓冲区,以容纳该行所需的任何大小。例如,你的逐行读文件循环可能如下所示:

while (1) {
        len = getline(&line_buf, &line_max, stdin);
        if (len < 0)
            break;

        // line_buf has len characters of data in it, and line_buf[len] == '\0'.
        // If the input contained embedded '\0' bytes in it, then strlen(line_buf) < len.
        // Normally, strlen(line_buf) == len.
    }

    free(line_buf);
    line_buf = NULL;
    line_max = 0;

    if (!feof(stdin) || ferror(stdin)) {
        // Not all of input was processed, or there was an error.
    } else {
        // All input processed without I/O errors.
    }

注意free(NULL)是安全的,它什么也不做。这意味着我们可以在循环后安全地使用free(line_buf); line_buf = NULL; line_max = 0;--事实上,在任何我们想要的地方!--来丢弃当前的行缓冲区。如果需要,下一个使用相同变量的getline()getdelim()调用将分配一个新的行缓冲区。
上面的模式从不会泄漏内存,并且可以正确地检测文件处理过程中的所有错误,从I/O错误到没有足够的RAM可用(或当前进程所允许的),尽管它无法区分它们:它也不会有假错误,除非你在你自己添加的处理代码中跳出循环。
因此,任何声称getline()“有漏洞”的说法都是反POSIX、亲微软的宣传。出于某种原因,微软一直拒绝在他们自己的C库中实现这些功能,尽管他们很容易做到。
如果你想复制一行的一部分,我推荐使用strdup()strndup(),它们也是POSIX.1-2008函数。它们返回一个动态分配的字符串副本,后者只复制指定的字符数(如果字符串在此之前没有结束);在所有情况下,如果函数返回一个非NULL指针,则动态分配的字符串以nul '\0'终止,并且在不再需要时,应该像上面的getline()缓冲区一样使用free()释放。
如果您还必须在Microsoft上运行代码,一个好的选择是在没有提供getline()的架构和操作系统上实现您自己的getline()。(您可以使用Pre-defined Compiler Macros Wiki来查看如何检测在特定架构、操作系统或编译器上编译的代码。)
一个getline()实现的例子可以写在fgets()的上面,增长缓冲区并读取更多的内容(追加到现有缓冲区),直到缓冲区以换行符结束。但是,它不能真正处理数据中嵌入的“\0”字节;要做到这一点,并正确实现getdelim(),您需要使用fgetc()逐字符读取数据。

相关问题