我一直在阅读很多答案,对此有很多意见,但我找不到能够回答我问题的代码(我发现很多代码都回答“如何分享”变量通过声明“)
情况如下:
现在已经不在了,让我写一个例子。
?maxperiod(13,911,11584577)
True
- 监控
file1.c
void function(){
uint8_t varFlag[10]; // 10 devices
for (uint8_t i = 0; i < 10; i++)
{
while (timeout <= 0){
varFlag[i] = 1;
// wait for response. We'll know by the ack() function
// if response back from RX,
// then varFlag[i] = 0;
}
- RX方
file2.c
答案 0 :(得分:3)
您共享值或数据,而不是变量。 Stricto sensu,变量在运行时不存在;只有编译器知道它们(最多使用-g
,它可能会在调试部分中放置一些元数据,例如偏移和类型的本地化 - 通常在可执行文件的生产代码中被删除)。 Ther链接器符号表(用于全局变量)可以并且通常在嵌入式发布的ELF二进制文件中被剥离。在运行时,您有一些数据段,可能是call stack由调用帧组成(在某些插槽中包含一些局部变量,即它们的值)。在运行时,只有位置是相关的。
(某些嵌入式处理器对其调用堆栈有严格限制;其他嵌入式处理器的RAM或暂存器内存有限;因此了解您所针对的实际处理器和ISA会有所帮助,并且你有多少RAM的想法
所以有一些全局变量保留这些共享值(可能间接通过一些指针和数据结构),或通过参数传递这些值(可能是间接的,同样......)。
因此,如果您想共享十个字节varFlag[10]
数组:
您似乎不希望将uint8_t varFlag[10];
声明为全局(或static
)变量。你确定你真的不应该(这十个字节必须坐在某个地方,而且他们确实消耗了一些RAM,可能在你的调用堆栈中......)?
传递varFlag
(数组,作为参数传递时衰减到指针)作为参数,所以可能声明:
void ack(uint8_t indexDevice, uint8_t*flags);
并从ack(3,varFlag)
...
function
或声明一个全局指针:
uint8_t*globflags;
并在函数开头设置它(使用globflags = varFlag;
),将varFlag
声明为局部变量,并在该函数的末尾清除if(使用globflags = NULL;
)。 / p>
我建议您查看编译器生成的汇编程序代码(使用GCC编译,可以使用gcc -S -Os -fverbose-asm -fstack-usage
....编译。我还强烈建议您让同事审核您的代码......
PS。也许您应该使用GCC或Clang/LLVM作为交叉编译器,也许您的 IAR 实际上正在使用这样的编译器......
答案 1 :(得分:1)
将函数放入单独的translation unit并使用static
变量:
static type var_to_share = ...;
void function() {
...
}
void ack() {
...
}
注意我说翻译单位,不是文件。你可以做一些#include
魔术(以最干净的方式)来保持两个功能定义。
答案 2 :(得分:1)
您不使用全局变量的论点:
与保持内存大小相关的一些事情,因此局部变量在范围的末尾消失,但全局变量保持不变。局部变量作为输出发送出去,因此我们立即丢弃它们,因为我们不需要它们
将生命周期与范围混淆。无论范围(或可见性)如何, static 生命周期的变量都会永久占用内存。具有全局范围的变量也恰好是静态分配的,但是任何其他静态变量也是如此。
为了跨上下文共享变量,它必须是静态的,因此通过避免全局变量不会节省内存。然而,有许多其他更强大的论据可以避免全局变量,你应该阅读Jack Ganssle撰写的A Pox on Globals。
C支持三个级别的范围:
其中第二个允许变量在同一源文件中的函数之间直接可见,而外部链接允许多个源文件之间的直接可见性。但是,在大多数情况下,您希望避免直接访问,因为这是全局变量的基本问题的根源。您可以使用访问器功能执行此操作;要使用您的示例,您可以添加包含以下内容的file3.c
#include "file3.h"
static uint8_t varFlag[10];
void setFlag( size_t n )
{
if( n < sizeof(varFlag) )
{
varFlag[n] = 1 ;
}
}
void clrFlag( size_t n )
{
if( n < sizeof(varFlag) )
{
varFlag[n] = 0 ;
}
}
uint8_t getFlag( size_t n )
{
return varFlag[n] == 0 ? 0 : 1 ;
}
使用关联的头文件3.h
#if !defined FILE3_INCLUDE
#define FILE3_INCLUDE
void setFlag( size_t n ) ;
void clrFlag( size_t n ) ;
uint8_t getFlag( size_t n ) ;
#endif
包含file1.c和file2.c,以便他们可以通过访问者函数访问varFlag[]
。好处包括:
varFlag[]
无法直接访问批判性地避免全局变量不会保存你的内存 - 数据仍然是静态分配的 - 因为你不能得到任何东西varFlag[]
必须存在,即使它是不可见。也就是说,关于内部表示的最后一点确实提供了存储效率的潜力,因为您可以将标志表示从uint8_t更改为单个位标志,而无需更改数据接口或访问访问代码:
#include <limits.h>
#include "file3.h"
static uint16_t varFlags ;
void setFlag( size_t n )
{
if( n < sizeof(varFlags) * CHAR_BIT )
{
varFlags |= 0x0001 << n ;
}
}
void clrFlag( size_t n )
{
if( n < sizeof(varFlags) * CHAR_BIT )
{
varFlags &= ~(0x0001 << n) ;
}
}
uint8_t getFlag( size_t n )
{
return (varFlags & (0x0001 << n)) == 0 ? 0 : 1 ;
}
还有更多机会生成健壮的代码,例如,您可能只将读访问器(getter)公开显示并隐藏,以便除一个翻译单元之外的所有代码都具有只读访问权限。
答案 3 :(得分:0)
不幸的是,您无法使用C。
做到这一点的唯一方法是要有毅力。