【问题标题】:In a C program, is it possible to reset all global variables to default vaues?在 C 程序中,是否可以将所有全局变量重置为默认值?
【发布时间】:2010-09-13 22:22:50
【问题描述】:

我有一个需要重用的遗留 C Linux 应用程序。这个应用程序使用了很多全局变量。我想重用这个应用程序的主要方法并在循环中调用它。我发现当我在循环中调用 main 方法(重命名为 callableMain)时,应用程序的行为并不一致,因为上一次迭代中设置的全局变量的值会影响新迭代中的程序流程。

我想做的是在执行新迭代之前将所有全局变量重置为默认值。

比如原来的程序是这样的

OriginalMain.C

#include <stdio.h>

int global = 3; /* This is the global variable. */

void doSomething(){     
         global++; /* Reference to global variable in a function. */    
}    

     // i want to rename this main method to callableMain() and
     // invoke  it in a loop 
     int main(void){    
       if(global==3) {    
       printf(" All  Is Well \n");    

       doSomething() ;  
     }
     else{

       printf(" Noooo\n");  

       doNothing() ;

     }
     return 0;
}

我想把这个程序改成如下:

我将上面的文件改名为 main() 为 callableMain()

而我新的主要方法如下:

int main(){  

     for(int i=0;i<20;i++){  

         callableMain();

         // this is where I need to reset the value of global vaiables
        // otherwise the execution flow  changes
     }    
}   

这是否可以在调用 main() 之前将所有全局变量重置为值?

简短的回答是没有可以重置全局变量的神奇 api 调用。全局变量必须被缓存和重用。

【问题讨论】:

  • 没有自动执行此操作的方法。考虑使用自动代码扫描来检测所有全局变量。此外,函数级静态也有助于全局状态。还有 RTL 的状态(打开的句柄等)。
  • 从下面的所有回复来看,你是对的,我需要自动代码扫描来检测所有全局变量。您能否推荐任何可以检测所有全局变量和函数级静态变量的工具(基于 Linux)。
  • 如果你想让一切都恢复到原来的状态,那么简单地运行可执行文件 20 次有什么问题?
  • 梦想:性能,通常。

标签: c global-variables


【解决方案1】:

我会将其作为子流程调用,并根据需要修改其输入和输出。让操作系统为你做这些脏活。

我们的想法是通过将旧程序与新程序降级到自己的进程来将其与新程序隔离开来。然后你在两者之间有一个干净的分离。此外,每次运行旧程序时,它都会重置为干净状态。

首先,修改程序,使其从文件中读取输入数据,并将其输出以机器可读格式写入另一个文件,文件在命令行中给出。

然后您可以创建命名管道(使用mkfifo 调用)并使用system 调用遗留程序,在命令行上将命名管道传递给它。然后你输入它的输入并读回它的输出。

我不是这些问题的专家;可能有更好的方法来进行 IPC。这里的其他人提到了fork。然而,分离遗留代码并将其作为子进程调用的基本思想可能是这里最好的方法。

【讨论】:

  • 这听起来很有希望。我正在寻找使用操作系统级别的 API 校准来为我完成这项工作。您能否详细说明您的方法?
【解决方案2】:

fork() 早点?

您可以在早期的某个时间点 fork(2) 当您认为全局变量处于良好状态时,然后让孩子在管道或其他东西上等待一些工作要做。这将需要将任何更改的状态或至少将结果写回父进程,但会将您的工作人员与您的主要控制进程分离。

事实上,fork() 至少两次可能是有意义的,一次是设置一个工作控制器并保存已初始化(但不是太初始化:-)的全局状态,然后再次拥有这个工作控制器 fork()对于您需要运行的每个循环。

一个更简单的变化可能是只修改代码,以便进程可以在“工作模式”下启动,然后使用fork() 或system() 在顶部启动应用程序,但带有一个参数进入从模式。

【讨论】:

  • 或者类似地,exec,如果可用并且您知道如何识别可执行文件。
【解决方案3】:

有一种方法可以在某些平台/编译器上执行此操作,您基本上会在调用 main() 之前执行编译器执行的相同初始化。

我已经为 TI DSP 完成了此操作,在这种情况下,我将带有全局变量的部分映射到内存的特定部分,并且有可用的链接器指令声明变量指向该部分的开头和结尾(这样您就可以memset() 整个区域在开始初始化之前归零)。然后,编译器提供了一个记录列表,每个记录都包含一个地址、数据长度和要复制到地址位置的实际数据。因此,您只需遍历记录并在目标地址中执行 memcpy() 以初始化所有全局变量。

非常特定于编译器,因此希望您使用的编译器允许您执行类似的操作。

【讨论】:

  • :-D 是的,确实很危险。但是,如果您不是生活在边缘(尤其是在引导加载程序项目中),那么编写 C 语言的乐趣在哪里!
【解决方案4】:

简而言之,没有。在这种情况下,我要做的是创建定义、常量(如果您愿意),然后使用它们来重置全局变量。

基本上

#define var1 10
int vara = 10

等等...基本的 C 语言对吗? 然后,您可以继续将重新初始化包装在一个方便的函数中 =)

【讨论】:

    【解决方案5】:

    我认为你必须改变看待问题的方式。

    在 callableMain() 的主体中声明 callableMain() 使用的所有变量,因此它们不再是全局变量,并且在函数执行后被销毁,并在您调用 callableMain() 时使用默认值再次创建下一次迭代。

    编辑:

    好的,如果您有 callableMain() 的源代码,您可以执行以下操作:在函数的开头,添加一个检查以验证它是否是第一次调用该函数。在此检查中,您会将使用的所有全局变量的值复制到另一组 static 变量(随意命名)。然后,在函数体上,将所有出现的全局变量替换为您创建的静态变量。

    这样您将保留所有全局变量的初始值,并在 callableMain() 的每次迭代中使用它们。这对你有意义吗?

    void callableMain()
    {
      static bool first_iter = true;
    
      if (first_iter)
      {  
        first_iter = false;
        static int my_global_var1 = global_var1;
        static float my_global_var2 = global_var2;
        ..
      }
    
      // perform operations on my_global_var1 and my_global_var2, 
      // which store the default values of the original global variables.
    
    }
    

    【讨论】:

    • 这是不可行的,因为全局变量正在被不同模块中的不同函数访问。这样做会导致过多的编译器错误。
    • 如果变量不再是全局变量,它们将无法被 callableMain() 之外的函数访问,例如问题中的 doSomething() 函数。
    • 他不想重写整个程序;这就是问题的重点。
    【解决方案6】:
    for (int i = 0; i < 20; i++) {
        int saved_var1 = global_var1;
        char saved_var2 = global_var2;
        double saved_var3 = global_var3;
    
        callableMain();
    
        global_var1 = saved_var1;
        global_var2 = saved_var2;
        global_var3 = saved_var2;
    }
    

    或者你可以找出全局变量从哪里开始memcpy他们。但是在开始循环时我总是会畏缩......

    for (int i = 0; i < 20; i++) {
        static unsigned char global_copy[SIZEOFGLOBALDATA];
        memcpy(global_copy, STARTOFGLOBALDATA, SIZEOFGLOBALDATA);
    
        callableMain();
    
        memcpy(STARTOFGLOBALDATA, global_copy, SIZEOFGLOBALDATA);
    }
    

    【讨论】:

      【解决方案7】:

      如果你不想重构代码并封装这些全局变量,我认为你能做的最好的就是定义一个重置函数,然后在循环中调用它。

      【讨论】:

        猜你喜欢
        • 2011-03-17
        • 2012-09-11
        • 1970-01-01
        • 2017-06-09
        • 1970-01-01
        • 2012-08-14
        • 2013-12-13
        • 1970-01-01
        • 2017-03-10
        相关资源
        最近更新 更多