我一直在尝试使用C
中的Keil
为我的TM4C123G
编写一些测试代码,该代码使用ARM
微控制器。我对ARM assembly
一无所知,但我过去曾为AVR microcontroller
编写了一些汇编代码。
如果我们将C中的变量声明为global
,而不是在main
中声明变量,那么存储变量的值在哪里?
是否应该声明一个变量global
而不是main
(在为微控制器编写C时)是否有一般指导原则?
答案 0 :(得分:2)
ARM中的Globals导致在调用函数的“池”区域中放置偏移量。通常,每个全局都需要自己的偏移量。如果您决定使用全局变量,请将它们放在一个结构中,以便可以通过单个池偏移来访问所有变量。
在功能级定义的变量存在于堆栈中。在合理范围内,这些可以通过与堆栈寄存器更简单的偏移来访问,并且往往是一种更有效的操作码操作,并且可能是缓存方式,具体取决于您使用的系统类型。
何时使用?除了可维护性的全球与本地神圣战争之外,它还归结为您的代码想要做的其他事情。如果某些变量被用于大量的地方并且您不希望将其作为参数传递(这可能是您的设计需要工作的标志......)那么全局化将是最佳选择。如果你需要在多个汇编程序包中访问这个变量(再次设计那个......)那么全局也许就好了。
大多数情况下,我会选择局部变量。它们更加线程安全,从上面来看,往往更有效。它们也更容易维护,因为范围更加狭窄 - 这也有助于编译器更好地完成工作。
答案 1 :(得分:1)
还有"静态"变量。它们的功能与全局变量的功能相同,但命名空间更为有限。它们用作文件局部变量和函数局部变量,它们在函数调用之间保持它们的值。
答案 2 :(得分:0)
Globals很好,他们在微控制器之类的嵌入式产品中占有一席之地,在这些产品中你的资源非常紧张。 Globals可让您轻松管理当地人非常充满活力的资源,最大限度地避免遇到麻烦。
但是......就集会而言,没有规则,没有真正的本地与全球的概念,严格来说是更高层次的语言。现在可能有汇编语言的实现允许/强制执行此类操作,理解C是跨平台的标准(与其他人一样)并且不是特定于一个。但是汇编不仅没有标准,而且也是处理器特定的。汇编语言由汇编程序(解析它并将其转换为机器代码的程序)定义。任何人和他们的兄弟都可以敲出一个汇编程序,并编写他们想要的任何语言或规则。
一般情况下,如果您尝试在汇编中实现C代码而不是让编译器执行它(或者只是让编译器执行它,至少看看它做了什么)。除非经过优化,否则你的全局变量将在ram中获得一个家。本地人可能会或可能不会取决于优化在堆栈上占有一席之地,他们可能只是暂时存在于寄存器中,取决于可用寄存器的处理器数量,在保留包含其他内容的寄存器之间进行权衡以保留本地以支持保留注册表中的其他内容。
您应该只使用一些简单的函数(不一定是完整的程序)并查看编译器的功能。
如果你想用纯粹的程序集编写并且没有转换C的概念,你仍然会遇到同样的困境,我会把某些东西放在寄存器中很长一段时间,我是否会把它放在堆栈中持续一段时间这段代码还是我给它分配了一个永远存在的地址。
我建议你思想开放,并试着理解为什么不做,为什么不做,很多这些规则,没有全局,小函数等都不是因为事实而是因为信仰,我信任的人告诉我们我所以我也是这样讲的,并不总是,但有时候你可以深入挖掘,发现恐惧是真实的,或恐惧是不真实的,或者可能是30年前应用但不再适用,等等。例如,全局的替代方法是在嵌套时向下传递的main()或top级的本地,这基本上意味着从资源角度来看它是全局的。实际上,取决于编译器(特别是非常流行的),传递下来的一个主级本地实际上消耗了每个嵌套级别的资源,消耗的ram数量比刚刚被声明为全局的更多。另一方面,如果它不是低效的内存消耗但访问,谁可以搞乱这个变量,谁不能,当地人使这很容易,相当多的懒惰,你可能是凌乱的。必须小心全局,不要搞砸他们。注意静态本地也是资源角度的全局变量,它们在程序的持续时间内位于相同的.data空间中。
有一个原因,很多原因导致C不能死。什么都没有,可以取代它。有一个原因,它基本上是每个新处理器/指令集的第一个编译器。
编写一些简单的函数,编译它们,反汇编,看看产生了什么。为这些平台采用一些嵌入式/裸机应用程序,反汇编,看看编译器做了什么。无法优化的Globals和static locals在.data中获取地址。有时一些或所有传入参数都会获得堆栈位置,有时一些或所有局部变量也会消耗堆栈,如果选择优化,则与编译器和优化有关。还取决于体系结构CISC可以做存储器和寄存器或存储器到存储器操作不必一直移入和移出寄存器RISC经常必须专门使用寄存器或经常使用寄存器,但也经常有很多更多可用。因此,编译器知道并管理变量的主页。
每个人都要将全局变量和静态局部变量放在ram中(除非它们可以优化)。传统的x86无论如何都会将参数放在堆栈中,并且会将本地人放在那里,只是在那里访问它们。 mips或arm将尝试最小化ram的使用量,并依赖于寄存器,试图将一些变量专门保留在寄存器中而不消耗堆栈。
汇编程序员,预编译器,使用了很多等价的全局变量,为每个变量选择一个地址。现在发布编译器,您可以选择以这种方式设置所有变量,除了从调用返回之外几乎不使用堆栈,或者您可以编程,就像您是编译器并制定一些规则或只是遵循编译器约定和有一些一次性寄存器和其他保留,并依靠堆栈保存和功能项本地。
在一天结束时虽然程序集没有全局vs本地的概念,但它有一个signed vs unsigned vs pointer vs array或者类似高级语言的概念。