我正在兜圈子,试图弄清楚如何实现需要由 [.c] 文件中的多个函数访问的变量。
我一直在 Stack Exchange 和其他 Google 搜索中逐个线程地研究,其中普遍 [但肯定不是一致的] 共识似乎是文件范围的静态变量很好,但是,您应该传递变量(或至少是指针到变量)到函数中,而不仅仅是让任何旧函数访问静态文件范围的变量(即在任何函数之外声明的变量)。有人说文件范围的静态变量本质上与全局变量一样糟糕,但没有说明如果不使用文件范围的静态变量,如何避免全局变量!
但是,在某些时候,即使您将指向文件范围静态变量的指针从一个函数传递到另一个函数,某些函数也必须最初访问该文件范围的静态变量。此外,我看不到 .c 文件中只有一个函数可以作为访问该静态变量的唯一函数的方式,因为并非所有需要静态变量的函数都会通过一个函数。
在我看来,您可以拥有一个除了保存一个静态变量并返回指向该静态变量的指针之外什么都不做的函数。任何需要访问该变量的函数都会调用该函数,获取指向该变量的指针并执行它需要对变量执行的操作。这种事情:
struct PacketStruct* GetPacketStructPtr(void)
{
static struct PacketStruct Packet;
return &Packet;
}
我看到这里有些人说,是的,这就是单件工厂的建造方式(无论如何)并且它是完全有效的,但其他人说这很危险(但没有真正解释为什么它很危险),其他人说这是不好的做法(我认为他们说它效率低下,但我今天读了这么多我可能是错的)。
所以,我想确定的是:
文件范围的变量可以吗?
如果是这样,考虑到让所有函数访问该文件范围的静态变量而不将指针传递给它[静态文件范围变量]似乎是错误的 - 尽可能多地使函数与不同的变量重用成为可能- 你可以决定需要访问文件范围静态的第一个函数这样做,然后将指针一直向下传递给其他函数吗?我真的很讨厌只访问文件范围的静态变量的代码的外观,即使传递一个指向函数无论如何都可以访问的东西的指针似乎也有点愚蠢。
如果文件范围的静态变量无效,鉴于这不是多线程的,而只是嵌入式微上的运行完成程序,我可以/应该使用这种方式将指针传递给函数范围的静态变量到需要访问该变量的任何其他函数?
如果以上都不是,你究竟如何避免可怕的全局变量?这个不使用全局变量的问题在这里似乎已经解决了无数次,但没有任何具体的例子来说明如何做到这一点。这里有很多相互矛盾的建议,更不用说在网络的其余部分了!
我强调这是单线程,不是可重入的,而且都相对简单。
希望这能让我对我正在尝试做的事情有更多的了解:
#include "work_order.h
// This is work_order.c
// Nothing outside of this file needs to access the WorkOrder struct
static struct WorkOrderStruct WorkOrder;
// Package up a work order - *data is a pointer to a complete serial package
int16_t CableConnectOrder(uint8_t *Data)
{
if (UnpackagePortInformation(&WorkOrder.PortA,&Data) == CARD_UID_NOT_FOUND)
return CARD_UID_NOT_FOUND;
if (UnpackagePortInformation(&WorkOrder.PortB,&Data) == CARD_UID_NOT_FOUND)
return CARD_UID_NOT_FOUND;
AddNewKeysToWorkOrder(&WorkOrder,Data);
WorkOrder.WorkOrderType = CONNECT_CABLE_REQUEST;
WorkOrder.Flags.SingleEndedConnection = FALSE_BIT;
WorkOrder.Flags.PortACableRemoveRequest = FALSE;
WorkOrder.Flags.PortBCableRemoveRequest = FALSE;
return ConstructCableOrderRequest(&WorkOrder);
}
int16_t ConstructCableOrderRequest(struct WorkOrderStruct *WorkOrder)
{
// This function is accessed by other Work Order requests and does the rest of the // packaging of the work order
// It can also pass the work order information further down
DoOtherStuff(WorkOrder); // Kind of further passing that might happen
}
int16_t CheckAdditionalInfoAgainstWorkOrder(struct WorkOrderPortUpdateStruct *Update)
{
// Compare connection information against the previously set-up work order
// Needs to access the static WorkOrder structure as well. Also, can call other
// functions that needs to access the static function
WorkOrder.Foo = Update->bar;
DoYetMoreOtherStuff(&WorkOrder); // This is not real code, but the general kind of idea
}