![]() |
1
8
嵌入式系统很奇怪,有时也有例外的“标准”C。 从一个系统到另一个系统,您将有不同的方法来执行诸如声明中断、定义内存不同段中的变量、运行“intrinsics”(直接映射到汇编代码的伪函数)或执行内联汇编代码之类的操作。 但是控制流(for/if/while/switch/case)以及变量和函数声明的基础应该是完全相同的。 这不是C语言的一部分;这是设备支持库的一部分。这是每个制造商必须记录的。 |
![]() |
2
18
不,有ISO C标准。由于许多小型设备具有需要支持的特殊体系结构特性,因此许多编译器支持语言扩展。例如,因为8051具有位可寻址RAM
因为Windows API是标准化的(微软),它只在x86上运行,所以没有考虑架构上的变化。也就是说,你仍然可以看到 FAR ,和 NEAR API中的宏,这是对16位x86及其分段寻址的回溯,这也需要编译器扩展来处理。
例如。。。? 我怀疑。再一次;例如。。。?
这不是由于语言或编译器的变化,更可能是简单的“预处理器魔法”。在AVR上,所有I/O都是内存映射的,因此,例如,如果您包括设备支持标头,则它可能具有如下声明:
要将0xFF写入内存,请映射地址0x100处的寄存器。你只需要看看头文件,看看它到底是怎么做的。 here 第6.36.8节和 3.17.3 . 如果您将其与GCC支持的其他目标进行比较,它的扩展很少,这可能是因为AVR体系结构和指令集是专门为干净高效地实现C编译器而设计的,没有扩展。
重要的是要认识到,C编程语言是一个不同于其库的实体,库提供的函数与您自己编写的函数没有区别——它们不是语言的一部分——因此它可以是没有库的C。最终,库函数是使用相同的基本语言元素编写的。您不能期望win32api中存在的抽象级别存在于为微控制器设计的库中。在大多数情况下,您至少可以期望 C Standard Library 多年来,我一直在为嵌入式和桌面系统编写C和C++,并且不认识到你所感知到的巨大差异,所以只能假设它们是对C语言构成的误解的结果。以下几本书可能会有所帮助。 |
![]() |
3
6
C语言假定 von Neumann 至于如何访问设备寄存器——在不同的桌面/服务器类机器上,这也是非常不同的,但是由于为这些机器(Mac OS X、Windows、BSD或Linux)编写的在通用现代操作系统下运行的程序通常不会直接访问硬件,所以这不是一个问题。不过,有一些操作系统代码必须处理这些问题。这通常是通过定义宏和/或函数来实现的,这些宏和/或函数在不同的体系结构上以不同的方式实现,甚至在单个系统上有多个版本,这样驱动程序就可以为特定的设备(如以太网芯片)工作,而不管它是在同一个系统上 PCI 卡或USB加密狗(可能插入PCI插槽的USB卡),或直接映射到处理器的地址空间。
the C standard library
). 当没有通用操作系统或文件系统时,这些事情就没有意义了。
至于什么 AVR-GCC 而且它的库——有很多东西涉及到如何做到这一点。AVR是一个 Harvard architecture 具有内存映射设备控制寄存器、特殊功能寄存器和通用寄存器(内存地址0-31),以及用于代码和常量数据的不同地址空间。这已经超出了标准C的假设。一些寄存器(一般、特殊和设备控制)可以通过特殊指令访问,例如翻转单个位和读/写到一些多字节寄存器(多指令操作)隐式地阻止下一条指令的中断(以便可以发生操作的后半部分)。这些都是桌面C程序不必知道的事情,因为AVR-GCC来自于常规的 GCC ,它最初也不了解所有这些东西。这意味着编译器不会总是使用最好的指令来访问控制寄存器,因此:
因为AVR通常必须在它的通用寄存器中有一些东西才能对它们进行位操作,尽管对于某些内存位置来说这是不正确的。必须对AVR-GCC进行修改,使其认识到当编译时已知某些操作中使用的变量的地址并且位于某个范围内时,它可以使用不同的指令来执行这些操作。在此之前,AVR-GCC只提供了一些宏(看起来像函数),这些宏有内联汇编来完成这项工作(并使用GCC现在使用的单指令实现)。如果它们不再提供这些操作的宏版本,那么这可能是一个错误的选择,因为它破坏了旧代码,但是一旦实现了高效和原子化的功能,就允许您像访问普通变量一样访问这些寄存器。 |
![]() |
4
5
我从来没有见过一个C编译器的微控制器没有一些控制器特定的扩展。一些编译器比其他编译器更接近于符合ANSI标准,但是对于许多微控制器来说,在性能和符合ANSI标准之间存在权衡。
在许多8位微控制器上,甚至在一些16位微控制器上,访问堆栈帧上的变量的速度很慢。有些编译器将始终在运行时堆栈上分配自动变量,尽管需要额外的代码来执行此操作;有些编译器将在编译时分配自动变量(允许从不同时存在的变量重叠),有些编译器允许使用命令行选项或
有些编译器有各种各样的内存存储类。通过将对象声明为合适的存储类,可以极大地提高性能。例如,一个 8051
如果一个人告诉8051编译器在默认情况下把所有的东西都放在“数据”中,那么如果一个人的变量总数超过96字节,而他没有指示编译器把任何东西放在其他地方,他就会“耗尽内存”。如果在默认情况下将所有内容都放在“扩展数据”中,则可以使用更多的内存而不受限制,但所有内容的运行速度都会变慢。最好是将直接访问的常用变量放在“data”中,将间接访问的常用变量和数组放在“idata”中,将不常用的变量和数组放在“xdata”中。 |
![]() |
5
2
绝大多数标准C语言都与微控制器通用。中断确实有稍微不同的约定,尽管不总是这样。 将端口视为变量是由于寄存器映射到大多数微控制器上内存中的位置,因此通过写入适当的内存位置(定义为内存中具有预设位置的变量),可以设置该端口上的值。 |
![]() |
6
1
正如前面的贡献者所说,主要由于不同的体系结构,没有这样的标准。
话虽如此,
Dynamic C
Rabbit Semiconductor
)被描述为“具有实时扩展的C”。据我所知,编译器只针对Rabbit处理器,但是还有一些有用的附加关键字(例如costate、cofunc和waitfor),一些真正的特性(例如,
|
![]() |
7
1
Wiring 具有基于C语言的语法。也许你想看看是什么使它如此。 |