重构大型事例语句、外部语句、静态局部语句

Refactoring large case statement, externs, static locals

本文关键字:语句 外部 静态局 重构 大型      更新时间:2023-10-16

我正在尝试进行一些重构,并希望找出最佳的前进道路。

我有

  myonce{
    static int i //for operation 1
    switch(commandid) {
       case 1:  operation 1
                i = 1;
       ...

其中myonce是在循环中调用的函数。这不是我的代码,我正在努力让它变得更好。操作1(或每种情况)是一系列命令,我想把它们放在自己的翻译单元中(每个文件一个函数)。

由于myonce在循环中运行,原始作者有许多静态变量用于保持状态,其中一些状态集用于多个操作。请注意,这些不是静态文件范围,而是静态块范围。

为了简单起见,作为概念的证明,我想知道以下是否可行。考虑使用1组静态变量的1个操作。

main.cpp

myonce {
   static int i //for op 1
   switch(commandid) {
       case 1:  operation1();

operation1.cpp

extern int i;
void operation1() {
   i = 1;
}

在多个操作使用相同的状态集的情况下,我会制作一个标头来声明它们都是外部的。

目前,这个文件的编译是以分钟为单位的,我的第一个目标是将它分解成更小的编译单元,以便作者可以更自由地工作。这种重构需要很长时间,但我提到这一点是为了解释我使用这种方法的动机。

我知道其他翻译单元(其他文件中的extern)无法访问静态文件范围变量,所以我想区分一下,我处理的不是这种情况。我现在不知道的是,我应该在哪里向main声明operation1(),它应该是吗

static int i
extern void operation1();

那么int被声明为对函数可见?

如果能在这方面提出任何建议,我将不胜感激。谢谢

将状态变量放入一个结构中。将此结构传递给每个函数。

示例。

// foo.h
struct TheState
{
    int x;
    char *y;
    // ...
};
void func1(TheState &);
void func2(TheState &);
// main.cc
#include "foo.h"
void main_loop()
{
     TheState the_state;  // initialize this however you want
     for (;;)
     {
          if ( blah) func1(the_state);
          else func2(the_state);
     }
}
// func1.cc
#include "foo.h"
void func1(TheState &the_state)
{
     ++the_state.x;
}

不,你不能那样做。static对象在其他源文件中永远不可见。

你的switch有多大?修改它的原因是什么?

也许最初的程序员有充分的理由使用局部静态变量?您说它是在循环中调用的,一些静态变量用于保持从一次迭代到下一次迭代的状态,在交换机的分支之间共享。这当然是一种奇怪的代码结构方式。我可以考虑做这样的事情来运行某种有限自动机,但在这种情况下,我会将自动机写成每个状态的一系列代码片段,并通过直接的goto s在它们之间传输。我会使确定在某个非常接近的地方,以更可读的形式对自动机进行描述。

但我可能完全偏离了底线。你能分享更多关于这个代码的功能吗?

首先,开关通常可以通过使用其函数创建更好的数据结构来避免(例如,具有虚拟成员函数command的类,其实现做了正确的事情)。

在一个不那么雄心勃勃的级别上,您可以将特定情况下所需的静态指针传递给函数,以便它可以读取和修改这些变量的状态。

根据函数的作用,还可以将状态信息作为值参数(副本)传递,让函数根据该状态进行工作,接收结果,然后根据结果更改主开关中的全局状态。然后状态变化是清晰可见的(即功能中没有副作用),并且嘈杂的分散注意力的细节被禁止进入另一个文件。

如果每种情况都倾向于使用许多静态变量,那么您可以将它们全部放在一个结构中;这种改变应该可以通过文本编辑器实现(用mystruct.x等替换变量名x)。然后每个函数只获得一个指向该结构的指针。编辑:正如我在评论中所说:也许命令自然地形成了只与状态的一部分有关的组(例如,有些命令只读取,其他命令只写入数据等)。然后,全局状态可以划分为相应的数据组。每个函数只能查看与其相关的数据组,这限制了潜在的副作用。

但总的来说,随着时间的推移,现在的功能似乎设计/发展得很糟糕;处理一大组静态变量意味着在代码中到处都有"副作用"——很难看出代码的任何给定部分是做什么的,以及它是如何与其他部分交互的。信息流并不明确。即使没有任何虚拟成员函数,分析属于一起的数据集群、将它们组织在类中并将它们分离在文件中也是一项任务。

至于您的最后一个问题:您创建的"case函数"(operation1();等)只需要在调用它们的文件中已知即可。如果它们在一个或多个单独的文件中,则应该创建一个包含原型的标头。