简体   繁体   English

Arduino / C ++ GlobalVars与局部变量

[英]Arduino/C++ GlobalVars vs Local variables

I'm working on an Arduino project right now. 我现在正在研究Arduino项目。 What it does is basically this: 它的作用基本上是这样的:

  1. Reads serial data from PC 从PC读取串行数据
  2. Parse received data 解析收到的数据
  3. Draw on TFT screen using this data. 使用此数据在TFT屏幕上绘制。

My current approach heavily utilizes global vars. 我当前的方法大量使用全局变量。 Without them, I'd have to use some nested functions that passes variables 3 levels deep. 没有它们,我将不得不使用一些嵌套函数,这些函数将变量传递给3级深度。 That got me thinking on which approach is better performance-wise. 这让我开始思考哪种方法在性能上更好。 Here are the two examples. 这是两个例子。

First the local: 首先本地:

void setup() {
  Serial.begin(9600);
  Serial.println(firstFunction(10));
}

int firstFunction(int val)
{
  return secondFunction(val+1);
}

int secondFunction(val)
{
  return thirdFunction(val+1);
}

int thirdFunction(val)
{
  return val + 1;
}

Global: 全球:

int x; //global var
void setup() {
  Serial.begin(9600);
  firstFunction(10);
  Serial.println(x);
}
void firstFunction(int val)
{
  x = val;
  x += 1;
  secondFunction();
}
void secondFunction()
{
  x++;
  thirdFunction();
}
void thirdFunction(val)
{
  x++;
}

On PC side of things, using globals are generally frowned upon. 在PC方面,通常不赞成使用全局变量。 But my understanding is that's mostly for styling and scalability reasons. 但是我的理解是,这主要是出于样式和可伸缩性的原因。

What you guys think? 你们怎么想?

In my opinion it is better to style to go for the local approach, also on the generally smaller Arduino programs. 在我看来,最好采用样式化以采用本地方法,在通常较小的Arduino程序上也是如此。 Once you have a lot globals you can them in a struct and pass the address of the struct to the functions. 一旦拥有很多全局变量,就可以将它们放在一个结构中,并将该结构的地址传递给函数。

Especially useful in the setup function, the memory is not occupied anymore once setup is done. 在设置功能中特别有用,设置完成后不再占用内存。 In your version x will still take up 4 bytes during the lifetime of the program. 在您的版本中,x在程序有效期内仍会占用4个字节。 With just 2k memory you can reach the limit fast. 仅有2k的内存,您可以快速达到极限。

I would do something like this: 我会做这样的事情:

typedef struct {
  int a, b;
} entity_t;

void foo(entity_t *e) { foo2(e); foo3(e); /* do stuff */ }

void setup()
{
  entity_t e = { 1, 2};

  foo(&e);

  Serial.println(e.a);
  // automatic memory of e is released
}

Depending on how complex your project is, either approach can be feasible. 根据项目的复杂程度,这两种方法都是可行的。

One consideration which speaks against passing variables as parameters through a stack of function calls is the very limited amount of memory you have on your microchip. 一个反对通过一堆函数调用将变量作为参数传递的考虑因素是,微芯片上的内存非常有限。 Every local variable and every function parameter is put on your stack, and in your case you have basically the same variable multiple times on the stack, wasting your memory. 每个局部变量和每个函数参数都放在堆栈中,在这种情况下,堆栈上多次具有基本上相同的变量,这浪费了内存。 Depending on the amount of RAM on your µC this can get hairy once you start working with strings and other larger structures you want to manipulate at runtime. 根据µC上的RAM数量,一旦开始使用字符串和要在运行时操作的其他较大结构,这可能会变得很麻烦。

If you notice that suddenly your µC starts misbehaving - crashes, hangs, produces garbage output, etc. - it can be that you are underflowing your stack into your heap or the other way round. 如果您发现您的µC突然开始行为异常-崩溃,挂起,产生垃圾输出等-可能是您正在将堆栈下溢到堆中,或者反过来。 This is less likely to become a problem if you try to avoid unnecessary copies of variables like this in the first place. 如果首先尝试避免不必要的变量副本,则这不太可能成为问题。

Of course, depending on how your program works, the opposite can be true: If you have to have some state you need to keep track of only in a certain part of your program, and you don't call many nested functions there, it is probably better to just keep it in local variables passed through, since then the variable will be gone again once you return from the outer function. 当然,根据程序的工作方式,情况可能相反:如果您必须具有某种状态,则只需要跟踪程序的某个部分,而无需在其中调用许多嵌套函数,最好将其保留在传递的局部变量中,因为从外部函数返回后,变量将再次消失。

Basically, the fundamental difference is that global variables are always there and occupy space through the whole time your program runs, while local variables do that only as long as the function which created them returns - but function arguments are like local variables of the function, so passing a variable through to another function creates a second copy. 从根本上说,根本的区别是全局变量始终存在并在程序运行的整个过程中都占据空间,而局部变量仅在创建它们的函数返回时才这样做-但是函数参数就像函数的局部变量一样,因此将变量传递给另一个函数会创建第二个副本。 So, it has always two sides. 因此,它总是有两个方面。

However, with increasing complexity, I'd definitely use classes - split by their responsibilities - with member or static variables and corresponding methods instead of just a bunch of global variables. 但是,随着复杂性的增加,我肯定会使用类(按其职责划分)以及成员或静态变量以及相应的方法,而不仅仅是一堆全局变量。

Then you still have things nicely tied together and not just all loosely floating around in global space, but you aren't wasting memory. 这样一来,您仍然可以将所有事物紧密地联系在一起,而不仅仅是在全球空间中松散地徘徊,而且您不会浪费内存。

I don't think adding a reference adds any overhead; 我认为添加引用不会增加任何开销; remember the compiler isn't tied to implementing it as pointer. 请记住,编译器并不局限于将其实现为指针。 If everything is in the same compilation unit, it can probably be optimized away. 如果所有内容都在同一编译单元中,则可能可以对其进行优化。 Almost certainly if the function is so small it can get inlined. 几乎可以肯定的是,如果函数很小,则可以内联。

A different possibility would be to make those functions and variables members of the same class, if the design allows it. 如果设计允许,则使这些函数和变量属于同一类的另一种可能性。

But at the end of the day, encapsulation mainly exists so that complex projects can be maintained over month or decades by shifting teams of programmers. 但归根结底,封装主要存在,因此,通过转移程序员团队,可以在一个月或几十年的时间内维护复杂的项目。 If it's a small code that only you will ever see, it's probably not necessary to get excessively tied to good practices. 如果只有一个小代码,您将永远看不到,那么就不必过多地与良好实践联系在一起。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM