代码之家  ›  专栏  ›  技术社区  ›  Chris Cooper

在C语言中,如果不包括“std”,你能做什么?它们是“C”的一部分,还是只是图书馆?

  •  43
  • Chris Cooper  · 技术社区  · 15 年前

    如果这是一个主观的或重复的问题,我道歉。搜索有点难,所以我不确定要包括哪些术语。

    我想知道的是,当不包括标准库时,C中的基本基础工具/函数是什么? stdio stdlib .

    如果没有我能做什么 printf() , fopen() 等?

    另外,这些库在技术上是“C”语言的一部分,还是它们只是非常有用和有效的基本库?

    10 回复  |  直到 8 年前
        1
  •  26
  •   Steve Jessop    15 年前

    C标准规定(5.1.2.3/5):

    对一致性的最低要求 实施包括:

    在序列点,易挥发的物体 在以前的意义上是稳定的 访问是完整的和后续的 尚未进行访问。

    项目终止时,所有数据 写入文件应相同 结果是执行 根据摘要编程 语义会产生。

    的输入和输出动态 应采用交互式装置。 如中所述 7.19.3.

    因此,如果没有标准的库函数,程序保证具有的唯一行为与易失性对象的值有关,因为您不能使用任何保证的文件访问或“交互设备”。纯C“仅通过标准库函数提供交互。

    不过,纯C并不是全部,因为您的硬件可能有特定的地址,这些地址在读或写时可以执行某些操作(无论是SATA或PCI总线、原始视频内存、串行端口、发出哔哔声的东西或闪烁的LED)。所以, 了解您的硬件 在不使用标准库函数的情况下,您可以用C编写大量的代码。可能,您可以实现C标准库,尽管这可能需要访问特殊的CPU指令以及特殊的内存地址。

    但是在纯C中,没有扩展,并且标准库函数被删除,基本上除了读取命令行参数、做一些工作以及从 main . 这是不值得注意的,它仍然是图灵完全服从资源限制,虽然您唯一的资源是自动和静态变量,没有堆分配。它不是一个非常丰富的编程环境。

    标准库是C语言规范的一部分,但在任何语言中,都会在语言“如此”和库之间画一条线。这是一个概念上的差异,但从原则上讲,最终并不是一个非常重要的差异,因为标准规定它们在一起。任何做非标准工作的人都可以像库一样轻松地删除语言功能。不管怎样,结果都不是C的一致实现。

    注意,C的“独立”实现只需要实现标准的一个子集,包括不包括任何I/O,所以您处于我上面描述的位置,即依赖特定于硬件的扩展来完成任何有趣的工作。如果您想根据标准在“核心语言”和“库”之间划一条界限,那么这可能是划一条线的好地方。

        2
  •  13
  •   plinth    15 年前

    你能做什么?一切!

    除了预处理器之外,C中没有什么魔力。

    最困难的可能是编写putchar——因为它依赖于平台的I/O。

    这是一个很好的本科生练习创建自己的varargs版本,一旦你得到了,做你自己的版本的vaprintf,然后printf和sprintf。

    1986年,当我对Lightspeed C提供的stdio程序不满意的时候,我在Macintosh上完成了所有的工作——用win-putchar、win-printf、in-getchar和win-scanf编写了我自己的窗口处理程序。

    这整个过程被称为引导,它可以是编码中最令人满意的体验之一-与一个基本的设计合作,使相当多的实际意义。

        3
  •  7
  •   Michael Burr    15 年前

    如果您不需要标准库,那么您当然没有义务使用它们。相当多的嵌入式系统要么没有标准库支持,要么出于某种原因无法使用它。该标准甚至专门讨论没有库支持的实现,c99标准5.1.2.1“独立环境”:

    在一个独立的环境中(在这种环境中,C程序的执行可能没有操作系统的任何好处),在程序启动时调用的函数的名称和类型是实现定义的。除第4条所要求的最小集合外,任何可供独立程序使用的库设施都是实现定义的。

    C99要求在独立实施中提供的头文件包括: <float.h> , <iso646.h> , <limits.h> , <stdarg.h> , <stdbool.h> , <stddef.h> <stdint.h> . 这些头只定义类型和宏,因此不需要函数库来支持它们。

    没有标准库,您就完全依赖于自己的代码、任何可能对您可用的非标准库,以及任何您可能能够连接到的操作系统调用(可能被视为非标准库调用)。很可能您必须让您的C程序调用汇编例程来连接设备和/或平台上的任何操作系统。

        4
  •  5
  •   Calmarius    8 年前

    如果没有printf()、fopen()等,我该怎么办?

    只要你知道如何连接你正在使用的系统,你就可以不使用标准的C库。在只有几千字节内存的嵌入式系统中,您可能根本不想使用标准库。

    这是一个你好的世界!不使用任何标准C函数的Linux和Windows上的示例:

    例如,在Linux上,可以直接在内联程序集中调用Linux系统调用:

    /* 64 bit linux. */
    
    #define SYSCALL_EXIT 60
    #define SYSCALL_WRITE 1
    
    void sys_exit(int error_code)
    {
        asm volatile
        (
            "syscall"
            : 
            : "a"(SYSCALL_EXIT), "D"(error_code)
            : "rcx", "r11", "memory"
        );
    }
    
    int sys_write(unsigned fd, const char *buf, unsigned count)
    {
        unsigned ret;
    
        asm volatile
        (
            "syscall"
            : "=a"(ret)
            : "a"(SYSCALL_WRITE), "D"(fd), "S"(buf), "d"(count)
            : "rcx", "r11", "memory"
        );
    
        return ret;
    }
    
    int _start()
    {
        const char hwText[] = "Hello world!\n";
    
        sys_write(1, hwText, sizeof(hwText));
        sys_exit(12);
    
        return 0;
    }
    

    编译时使用:

    gcc -nostdlib nostd.c 
    

    它输出 Hello world! ,然后退出。

    在Windows上,系统调用不会发布,而是隐藏在另一个抽象层kernel32.dll后面。无论您是否需要,它总是在程序启动时加载。因此,您可以简单地包括windows.h并使用win32 API:

    #include <windows.h>
    
    int _start()
    {
        const char str[] = "Hello world!\n";
        HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE);
        DWORD written;
    
        WriteFile(stdout, str, sizeof(str), &written, NULL);
        ExitProcess(12);
    
        return 0;
    }
    

    这个 windows.h 与标准C库无关,因为您也应该能够用任何其他语言编写Windows程序。

    您可以使用如下mingw工具编译它:

    gcc -nostdlib C:\Windows\System32\kernel32.dll nostdlib.c
    

    然后编译器就足够聪明,可以解决导入依赖项并编译程序。

    如果你分解程序,你只能看到你的代码在那里,里面没有标准的库膨胀。

    所以您可以在没有标准库的情况下使用C。

        5
  •  2
  •   WhirlWind    15 年前

    你不能做太多,因为大多数标准库函数依赖于系统调用;你只能使用内置的C关键字和操作符。它还依赖于系统;在某些系统中,您可能能够以某种方式操作位,从而产生一些外部功能,但这可能是例外,而不是规则。

    然而,C的优雅在于它的简单。与Fortran不同的是,它包含许多作为语言一部分的功能,C完全依赖于它的库。这给了它很大的灵活性,但代价是在不同的平台之间缺乏一致性。

    例如,在实现了完全独立的“库”的操作系统中,这很好地工作,以便在内核内部实现类似的功能。

    库的某些部分被指定为ANSIC的一部分;我想它们是语言的一部分,但不是其核心。

        6
  •  2
  •   Uri    15 年前

    它们都不是语言关键字的一部分。但是,所有C发行版都必须包含这些库的实现。这确保了 许多的 程序。

    首先,理论上可以使用C和汇编的组合来实现所有这些函数,所以理论上可以做任何事情。

    实际上,库函数主要是为了节省重新设计轮子的工作。有些东西(如字符串和库函数)更容易实现。其他事情(如I/O)很大程度上取决于操作系统。编写自己的版本对于一个O/S来说是可能的,但这会降低程序的可移植性。

    但是你可以写一些程序来做很多有用的事情(例如计算π或者生命的意义,或者模拟自动机)。但是,除非您直接将操作系统用于I/O,否则很难观察输出是什么。

    在日常编程中,编程语言的成功通常需要为许多有用的任务提供有用的高质量标准库和库。他们可以是第一方或第三方,但必须在那里。

        7
  •  2
  •   Rooke    15 年前

    std库是“标准”库,在C编译器要符合标准(如c99)的情况下,这些库必须是“可包含的”。有关一个可能有助于理解这意味着什么的有趣示例,请查看Jessica McKellar的挑战:

    http://blog.ksplice.com/2010/03/libc-free-world/

        8
  •  0
  •   Puppy    15 年前

    CRT是C语言的一部分,与关键字和语法一样多。如果您使用的是C,那么编译器必须为您的目标平台提供一个实现。

    编辑: 这和STL的C++是一样的。所有语言都有一个标准库。可能是汇编程序作为例外,或其他一些严重的低级语言。但大多数中/高水平的银行同业拆借利率都是标准的。

        9
  •  0
  •   tomlogic    15 年前

    这个 标准C库 是ANSI C89/ISO C90的一部分。我最近一直在为以前不符合ANSI的C编译器开发库。

    这本书 The Standard C Library P.J.Plauger为该项目提供了很好的参考。除了阐明标准的要求外,Plauger还解释了每个.h文件的历史以及一些API设计背后的原因。他还提供了库的完整实现,当标准中的某些内容不清楚时,这对我有很大帮助。

    该标准描述了15个头文件(包括stdio.h、stdlib.h,但也包括float.h、limits.h、math.h、locale.h等)中每个头文件的宏、类型和函数。

    除非包含标准库,否则编译器不能声明为ANSI C。

        10
  •  -2
  •   Qantas 94 Heavy user3381402    11 年前

    汇编语言有简单的命令,可以将值移动到CPU、内存和其他基本功能的寄存器中,还可以执行机器的核心功能和计算。C库基本上是汇编代码块。您也可以在C程序中使用汇编代码。var是汇编代码指令。当你使用 0x 在数字变成十六进制之前,这就是汇编指令。汇编代码是机器代码的可读形式,是电路路径实际开关状态的直观形式。

    因此,当机器代码(因此是汇编代码)内置于机器中时,C语言是各种预先形成的代码组合的组合,包括您自己的函数,这些函数可能是部分汇编语言,部分调用汇编语言或其他函数C库。所以汇编代码是所有编程的基础,然后是任何人对什么是什么的猜测。这就是为什么有如此多的语言和如此少的真正标准。