微控制器有什么特殊的 C 标准吗?
不,有 ISO C 标准。由于许多小型设备具有需要支持的特殊架构特性,因此许多编译器都支持语言扩展。例如,因为 8051 具有位可寻址 RAM,所以可以提供 _bit 数据类型。它还有一个Harvard architecture,因此提供了关键字来指定不同的内存地址空间,单独的地址无法解析这些地址空间,因为需要不同的指令来寻址这些空间。此类扩展将在编译器文档中明确指出。此外,符合标准的编译器中的扩展名应该带有下划线前缀。但是,许多为向后兼容提供了朴素的别名,应该不推荐使用它们。
...当我在 Windows 操作系统下编写程序时,我使用的编译器并不重要。
因为 Windows API 是标准化的(由 Microsoft),并且它只在 x86 上运行,所以不需要考虑架构变化。也就是说,您可能仍会在 API 中看到 FAR 和 NEAR 宏,这是对 16 位 x86 及其分段寻址的回归,这也需要编译器扩展来处理。
...即使它的基础仍然是 C,比如循环、变量创建等等,
我不确定这意味着什么。一个典型的微控制器应用程序没有操作系统或简单的内核,您应该期望看到更多的“裸机”或“系统级”代码,因为没有广泛的操作系统 API 和设备驱动程序接口来完成大量工作引擎盖给你。所有这些库调用就是这样;它们不是语言的一部分;它是相同的C语言;只是投入不同的工作。
...有一些我从未在桌面计算机的 C 语言中见过的语法类型。
例如...?
此外,语法随着版本的变化而变化。
我对此表示怀疑。再次;比如……?
我使用的是AVR-GCC编译器,在之前的版本中,你使用了一个端口I/O的函数,现在你可以像处理新版本中的变量一样处理端口了。
这不取决于语言或编译器的变化,而更可能是简单的“预处理器魔法”。在 AVR 上,所有 I/O 都是内存映射的,因此如果您包含设备支持标头,它可能有如下声明:
#define PORTA (*((volatile char*)0x0100))
然后你可以写:
PORTA = 0xFF;
将 0xFF 写入内存映射地址 0x100 的寄存器。你可以看看头文件,看看它到底是怎么做的。
GCC 文档描述了特定于目标的变体; AVR 在第 6.36.8 节和3.17.3 中专门处理了here。如果将其与 GCC 支持的其他目标进行比较,它的扩展很少,可能是因为 AVR 架构和指令集是专门为干净高效地实现没有扩展的 C 编译器而设计的。
什么定义了哪些函数以及如何将它们实现到编译器中并且仍然被称为 C?
重要的是要认识到 C 编程语言是与其库不同的实体,库提供的函数与您自己编写的函数没有什么不同——它们不是语言的一部分——所以它可以是C 没有任何库。最终,库函数是使用相同的基本语言元素编写的。您不能期望 Win32 API 中存在的抽象级别存在于用于微控制器的库中。在大多数情况下,您可以期望至少实现 C Standard Library 的一个子集,因为它被设计为具有很少目标硬件依赖关系的系统级库。
多年来,我一直在为嵌入式和桌面系统编写 C 和 C++,并没有认识到您似乎感知到的巨大差异,因此只能假设它们是对 C 语言构成的误解的结果。以下书籍可能会有所帮助。