如果这是一个主观或重复的问题,我道歉.搜索有点尴尬,所以我不确定要包含哪些术语.
我想知道的是当你不包括像stdio和的标准库时,C语言中的基础工具/功能是什么stdlib.
如果没有printf(),我该怎么办fopen()?
另外,这些库在技术上是"C"语言的一部分,还是只是非常有用且有效的基本库?
Ste*_*sop 29
C标准就是这样说的(5.1.2.3/5):
符合实施的最低要求是:
- 在序列点处,易失性对象在先前访问完成且后续访问尚未发生的意义上是稳定的.
- 在程序终止时,写入文件的所有数据应与根据抽象语义产生的程序执行的结果相同.
- 交互设备的输入和输出动态应按照7.19.3的规定进行.
因此,如果没有标准库函数,程序保证具有的唯一行为与易失性对象的值有关,因为您不能使用任何保证文件访问或"交互设备"."Pure C"仅通过标准库函数提供交互.
但是,Pure C并不是全部,因为您的硬件可能具有某些地址,这些地址在读取或写入时会执行某些操作(无论是SATA或PCI总线,原始视频内存,串行端口,还是要发出哔哔声,或者闪烁的LED).因此,了解您的硬件,您可以在不使用标准库函数的情况下在C中进行大量编写.可能您可以实现C标准库,尽管这可能需要访问特殊的CPU指令以及特殊的内存地址.
但是在纯C中,没有扩展,并删除了标准库函数,除了读取命令行参数,做一些工作,并从中返回状态代码之外,你基本上不能做任何事情main.虽然你的唯一资源是自动和静态变量,没有堆分配,但它仍然没有被嗅到,它仍然是图灵完全受资源限制.它不是一个非常丰富的编程环境.
标准库是C语言规范的一部分,但在任何语言中都倾向于在"如此"的语言和库之间划线.这是一个概念上的差异,但最终在原则上并不是一个非常重要的差异,因为标准说他们聚在一起.任何做非标准事情的人都可以像删除图书馆一样轻松删除语言功能.无论哪种方式,结果都不是C的一致实现.
请注意,C的"独立"实现只需要实现标准的子集,包括不包括任何I/O,因此您处于我上面描述的位置,依赖于特定于硬件的扩展来完成任何有趣的事情. .如果你想根据标准区分"核心语言"和"库",那么这可能是绘制线的好地方.
pli*_*nth 14
你能做什么?一切!
除了预处理器之外,C中没有魔法.
最难的,也许是写putchar - 因为这是平台相关的I/O.
创建自己的varargs版本是一个很好的本科练习,一旦你有了它,你可以使用自己的vaprintf版本,然后是printf和sprintf.
1986年,当我对使用Lightspeed C提供的stdio例程不满意时,我在Macintosh上完成了所有操作 - 使用win_putchar,win_printf,in_getchar和win_scanf编写了我自己的窗口处理程序.
整个过程称为bootstrapping,它可以是编码中最令人满意的体验之一 - 使用基本设计,具有相当大的实际意义.
如果您不需要它们,您当然没有义务使用标准库.相当多的嵌入式系统要么没有标准库支持,要么因某种原因无法使用它.该标准甚至专门讨论了没有库支持的实现,C99标准5.1.2.1"独立环境":
在独立环境中(可以在没有操作系统任何好处的情况下执行C程序),程序启动时调用的函数的名称和类型是实现定义的.除了第4节要求的最小集合之外,任何可用于独立程序的库设施都是实现定义的.
通过C99所要求的报头是在一个独立的实行都可以<float.h>,<iso646.h>, <limits.h>, <stdarg.h>, <stdbool.h>, <stddef.h>,和<stdint.h>.这些头只定义类型和宏,因此不需要函数库来支持它们.
如果没有标准库,您完全依赖于您自己的代码,可能可用的任何非标准库,以及您可能能够与之交互的任何操作系统系统调用(可能被视为非标准库)调用).很可能你必须让你的C程序调用程序集例程来连接设备和/或平台上的任何操作系统.
如果没有printf(),fopen()等,我该怎么办?
只要您知道如何连接您正在使用的系统,您就可以在没有标准C库的情况下生存.在只有几千字节内存的嵌入式系统中,您可能根本不想使用标准库.
这是一个Hello World!不使用任何标准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;
}
Run Code Online (Sandbox Code Playgroud)
用以下内容编译:
gcc -nostdlib nostd.c
Run Code Online (Sandbox Code Playgroud)
它输出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;
}
Run Code Online (Sandbox Code Playgroud)
这windows.h与标准C库无关,因为您应该能够使用任何其他语言编写Windows程序.
您可以使用MinGW工具编译它,如下所示:
gcc -nostdlib C:\Windows\System32\kernel32.dll nostdlib.c
Run Code Online (Sandbox Code Playgroud)
然后编译器足够聪明,可以解析导入依赖项并编译程序.
如果你反汇编程序,你只能看到你的代码在那里,其中没有标准的库膨胀.
因此,您可以在没有标准库的情况下使用C.