如果这是一个主观或重复的问题,我道歉。搜索有点尴尬,所以我不确定要包括哪些术语。
当您不包含stdio
和stdlib
等标准库时,我想知道C语言中的基本工具/功能是什么。
如果没有printf()
,fopen()
等,我该怎么办?
另外,这些库在技术上是“C”语言的一部分,还是只是非常有用且有效的基本库?
答案 0 :(得分:26)
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,因此您处于我上面描述的位置,依赖于特定于硬件的扩展来获取任何有趣的事情。如果你想根据标准区分“核心语言”和“图书馆”,那么这可能是画线的好地方。
答案 1 :(得分:13)
除了预处理器之外,C中没有魔法。
最难的,也许是写putchar - 因为这是依赖于平台的I / O.
创建自己的varargs版本是一个很好的本科练习,一旦你有了这个,你可以使用自己的vaprintf版本,然后是printf和sprintf。
我在1986年在Macintosh上完成了所有操作,当时我对使用Lightspeed C提供的stdio例程不满意 - 用win_putchar,win_printf,in_getchar和win_scanf编写了我自己的窗口处理程序。
整个过程称为bootstrapping,它可以是编码中最令人满意的体验之一 - 使用基本设计,具有相当大的实际意义。
答案 2 :(得分:7)
如果您不需要标准库,您当然没有义务使用标准库。相当多的嵌入式系统要么没有标准库支持,要么因某种原因无法使用它。该标准甚至专门讨论了没有库支持的实现,C99标准5.1.2.1“独立环境”:
在独立环境中(可以在没有操作系统任何好处的情况下执行C程序),在程序启动时调用的函数的名称和类型是实现定义的。除了第4章要求的最小集之外,任何独立程序可用的库设施都是实现定义的。
C99在独立实现中可用的标头是<float.h>
,<iso646.h>
,<limits.h>
,<stdarg.h>
,<stdbool.h>
,{{1} }和<stddef.h>
。这些头只定义了类型和宏,因此不需要函数库来支持它们。
如果没有标准库,您完全依赖于您自己的代码,可能可用的任何非标准库,以及您可能能够与之交互的任何操作系统系统调用(可能被视为非 - 标准库调用)。很可能你必须让你的C程序调用程序集例程来连接设备和/或平台上可能有的任何操作系统。
答案 3 :(得分:5)
如果没有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;
}
用以下内容编译:
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.
答案 4 :(得分:2)
你不能做很多事情,因为大多数标准库函数都依赖于系统调用;您仅限于使用内置C关键字和运算符可以执行的操作。它还取决于系统;在某些系统中,您可能能够以导致某些外部功能的方式操作位,但这可能是例外而不是规则。
然而,C的优雅在于它的简洁。与Fortran不同,它包含许多功能作为语言的一部分,C完全依赖于它的库。这使它具有很大的灵活性,但代价是从平台到平台的不一致性。这很好,例如,在操作系统中,实现了完全独立的“库”,以提供与内核本身内部实现类似的功能。
库的某些部分被指定为ANSI C的一部分;我认为它们是语言的一部分,但不是它的核心。
答案 5 :(得分:2)
它们都不是语言关键字的一部分。但是,所有C发行版都必须包含这些库的实现。这确保了许多程序的可移植性。
首先,理论上你可以使用C和汇编的组合自己实现所有这些功能,所以你理论上可以做任何事情。
实际上,库函数主要是为了节省您重新发明轮子的工作。有些东西(比如字符串和库函数)更容易实现。其他事情(如I / O)在很大程度上取决于操作系统。一个操作系统可以编写自己的版本,但这会降低程序的可移植性。
但是你可以编写做很多有用事情的程序(例如,计算PI或生命的意义,或模拟自动机)。但是,除非您直接将操作系统用于I / O,否则很难观察输出是什么。
在日常编程中,编程语言的成功通常需要为许多有用的任务提供有用的高质量标准库和库。这些可以是第一方或第三方,但必须在那里。
答案 6 :(得分:2)
std库是“标准”库,因为要使C编译器符合标准(例如C99),这些库必须是“包含”的。有一个有趣的例子可能有助于理解这意味着什么,请看看Jessica McKellar的挑战:
答案 7 :(得分:0)
CRT是C语言的一部分,与关键字和语法一样多。如果您使用的是C,那么您的编译器必须为您的目标平台提供实现。
编辑: 它与C ++的STL相同。所有语言都有标准库。也许汇编程序是例外,或者其他一些严重的低级语言。但大多数中/高级别都有标准库。
答案 8 :(得分:0)
标准C库是ANSI C89 / ISO C90的一部分。我最近一直在为一个以前不符合ANSI标准的C编译器开发库。
P.J. Plauger的书The Standard C Library是该项目的一个很好的参考。除了阐明标准的要求外,Plauger还解释了每个.h文件的历史记录以及一些API设计背后的原因。他还提供了图书馆的完整实施,当标准中的某些内容不明确时,这对我有很大帮助。
该标准描述了15个头文件中的每一个的宏,类型和函数(包括stdio.h,stdlib.h,还有float.h,limits.h,math.h,locale.h等)。 / p>
编译器不能声称是ANSI C,除非它包含标准库。
答案 9 :(得分:-2)
汇编语言具有简单的命令,可将值移动到CPU,内存和其他基本功能的寄存器,以及执行机器的核心功能和计算。 C库基本上是汇编代码的块。您还可以在C程序中使用汇编代码。 var是汇编代码指令。在数字之前使用0x
使其成为十六进制时,即汇编指令。汇编代码是机器代码的可读形式,它是电路路径的实际开关状态的可视形式。
因此,虽然机器代码和汇编代码都内置在机器中,但C语言是各种预先形成的代码组合的组合,包括您自己的函数,这些函数可能部分是汇编语言,部分是调用汇编语言或其他C库的其他函数。因此汇编代码是所有编程的基础,之后任何人都会猜测是什么。这就是为什么语言太多而真正的标准如此之少。
答案 10 :(得分:-2)
是的,没有库,您可以做很多事情。
救星在GCC中为__asm__
。这是一个关键字,所以可以。
主要是因为每种编程语言都是基于Assembly构建的,因此您可以直接在某些OS下进行系统调用。