如果没有“std”,你可以在C中做什么? 他们是“C”的一部分,还是仅仅是图书馆?
如果这是一个主观或重复的问题,我很抱歉。 这是一种尴尬的search,所以我不知道要包括什么条件。
我想知道的是当你不包含stdio
和stdlib
类的标准库时,C语言中的基本工具/函数是什么。
如果没有printf()
, fopen()
等,我该怎么办?
而且,这些库在技术上是“C”语言的一部分,还是仅仅是非常有用和有效的基础库?
C标准有这个说法(5.1.2.3/5):
符合实现的最低要求是:
– 在顺序点,易失性对象是稳定的,因为之前的访问已经完成,后续的访问还没有发生。
– 程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。
– 交互设备的input和输出dynamic应按照7.19.3的规定进行。
因此,如果没有标准的库函数,程序保证唯一的行为与易失性对象的值有关,因为不能使用任何有保证的文件访问或“交互式设备”。 “Pure C”仅通过标准库函数提供交互。
然而,纯粹的C不是全部,因为你的硬件可能有某些地址在读或写时做某些事情(不pipe是SATA还是PCI总线,原始video内存,串口,嘟嘟声或者闪烁的LED)。 所以, 了解你的硬件的一些东西 ,你可以用C语言写很多东西,而不需要使用标准的库函数。 可能的话,您可以实现C标准库,尽pipe这可能需要访问特殊的CPU指令以及特殊的内存地址。
但是在纯C中,没有扩展,并且除去了标准的库函数,除了读取命令行参数,做一些工作以及从main
返回一个状态代码之外,你基本上什么也做不了。 这不是嗅探,它仍然是图灵完全受资源限制,虽然你唯一的资源是自动和静态variables,没有堆分配。 这不是一个非常丰富的编程环境。
标准库是C语言规范的一部分,但是在任何语言中都倾向于在“本身”这样的语言和库之间画一条线。 这是一个概念上的差异,但最终不是一个非常重要的原则,因为标准说他们走到了一起。 任何人做非标准的东西都可以像库一样轻松地删除语言function。 无论哪种方式,结果都不是C的一致性实现。
请注意,C的“独立”实现只需要实现一个标准的子集,不包括任何I / O,所以你处于我上面描述的位置,依靠硬件特定的扩展来完成任何有趣的事情。 如果你想根据标准来区分“核心语言”和“图书馆”,那么这可能是一个划清界限的好地方。
你能做什么? 一切!
C中除了预处理器之外没有什么魔法。
最难的,也许是写putchar – 因为这是平台相关的I / O。
创build自己的可变参数版本是一个很好的本科练习,一旦你有了这个,做自己的版本的vaprintf,然后printf和sprintf。
在1986年,当我对Lightspeed C提供的stdio例程不满意的时候,我在Macintosh上做了所有的工作 – 用win_putchar,win_printf,in_getchar和win_scanf写了我自己的窗口句柄。
这整个过程被称为自举,它可以是最令人满意的编码体验之一 – 使用一个基本的devise,使其具有相当的实际意义。
如果你不需要它们,你当然没有义务使用标准库。 不lessembedded式系统都没有标准的库支持,或者因为某种原因不能使用它。 该标准甚至具体谈到没有库支持的实现,C99标准5.1.2.1“独立环境”:
在一个独立的环境中(C程序的执行可能没有任何操作系统的好处),程序启动时调用的函数的名称和types是实现定义的。 任何独立程序提供的图书馆设施,除第4条所要求的最低限度设置外,都是实施定义的。
C99所需的头文件在独立实现中可用: <float.h>
, <iso646.h>
, <limits.h>
, <stdarg.h>
, <stdbool.h>
, <stddef.h>
和<stdint.h>
。 这些头文件只定义了types和macros,所以不需要函数库来支持它们。
如果没有标准库,则完全依赖于您自己的代码,可能为您提供的任何非标准库以及您可能能够接口的任何操作系统调用(可能会将其视为非标准库调用)。 很可能你必须让你的C程序调用汇编例程来连接设备和/或平台上的任何操作系统。
如果没有printf(),fopen()等,我该怎么办?
只要你知道如何连接你正在使用的系统,你就可以没有标准的C库。 在只有几千字节内存的embedded式系统中,您可能根本不想使用标准库。
这是一个Hello World! 在Linux和Windows上不使用任何标准C函数的例子:
例如,在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而不用标准库。
你不能做很多事情,因为大部分的标准库函数都依赖于系统调用; 您仅限于使用内置的C关键字和运算符可以执行的操作。 这也取决于系统; 在某些系统中,您可能能够以某种外部function的方式操作位,但这可能是例外而不是规则。
然而,C的优雅是简单的。 与包含许多function的Fortran不同,C完全依赖于它的库。 这给了它一个很大程度的灵活性,代价是从平台到平台的一致性稍差。
例如,在完全分离的“库”被实现的操作系统中,这可以很好地工作,以在内核本身内提供类似的function。
库的某些部分被指定为ANSI C的一部分; 他们是我想的语言的一部分,但不是它的核心。
他们都不是语言关键字的一部分。 但是,所有的C发行版都必须包含这些库的实现。 这确保了许多程序的可移植性。
首先,理论上你可以使用C和汇编的组合来实现所有这些function,所以理论上你可以做任何事情。
实际上,图书馆function主要是为了节省你重新发明轮子的工作。 有些东西(比如string和库函数)更容易实现。 其他东西(如I / O)非常依赖于操作系统。 编写自己的版本将可能为一个操作系统,但它会使程序更便携。
但是你可以编写一些执行很多有用的事情的程序(例如,计算PI或者生命的意义,或者模拟一个自动机)。 除非你直接用I / O操作系统,否则很难观察输出是什么。
在日常编程中,编程语言的成功典型地需要为许多有用的任务提供有用的高质量标准库和库。 这些可以是第一方或第三方,但他们必须在那里。
标准库是“标准”库,因为要使C编译器符合标准(例如C99),这些库必须是“可包含的”。 有一个有趣的例子可以帮助理解这个意思,看看Jessica McKellar在这里的挑战:
CRT是C语言的一部分,就像关键字和语法一样。 如果你使用C,你的编译器必须为你的目标平台提供一个实现。
编辑:这与C ++的STL是一样的。 所有的语言都有一个标准库。 也许汇编语言是个例外,或者其他严重低级的语言。 但是大多数中/高级别都有标准库。
标准C库是ANSI C89 / ISO C90的一部分。 我最近一直在编译以前不符合ANSI的C编译器库。
PJ Plauger的“标准C库 ”一书是该项目的重要参考书。 Plauger除了阐述标准的要求之外,还解释了每个.h文件的历史和一些APIdevise背后的原因。 他还提供了图书馆的全面实施,当标准中的某些内容不明确时,这些帮助我大大提高了。
该标准描述了15个头文件(包括stdio.h,stdlib.h,还包括float.h,limits.h,math.h,locale.h等)的macros,types和函数。
编译器不能声称是ANSI C,除非它包含标准库。
汇编语言具有简单的命令,可将值移至CPU,内存和其他基本function的寄存器,并执行机器的核心function和计算。 C库基本上是汇编代码块。 您也可以在C程序中使用汇编代码。 var是汇编代码指令。 当你在一个数字之前使用0x
来使它成为hex,那就是汇编指令。 汇编代码是机器代码的可读forms,它是电路path的实际开关状态的可视forms。
因此,虽然机器代码以及汇编代码已内置在机器中,但是C语言是由各种预先形成的代码组合组成的,包括您自己的可能部分汇编语言的函数和部分调用其他函数汇编语言或其他C库的function。 所以汇编代码是所有编程的基础,之后就是人们对什么是什么的猜测。 这就是为什么有这么多的语言和真正的标准。