【问题标题】:Static variable initialization inside a function in CC中函数内的静态变量初始化
【发布时间】:2018-12-07 03:27:20
【问题描述】:

考虑以下函数

int16_t read_input(void)
{
   static int32_t previous_input = read_encoder(); // <--Not a compile time constant

   //Read current_input 

   if (previous_input - current_input > SOME_THRESHLD)
       some_action();

   previous_input = current_input;

   //some more code + return statement

}

由于变量未初始化为编译时常量,我无法在没有错误的情况下声明它。我想将变量保留为函数内的静态变量有两个原因

1) 该变量未在程序的其他任何地方使用。所以没有必要将其保留为全局变量

2) 前一个函数需要初始化为当前输入,否则在初始运行期间,由于编码器连接到当前输入,当前输入与前一个输入之间的差异可能会变得非常高(并且无法确定在哪里可能是编码器值,这取决于用户在关闭它之前旋转了多少)。这会造成其他功能的误触发。

有没有办法在函数内声明一个静态变量并将其初始化为类似于上面给出的示例的值?

注意:这个问题是复杂程序的一部分,我已对其进行了简化以避免复杂性。如果问题有任何歧义,请告诉我

【问题讨论】:

  • 我不清楚为什么静态在这里很重要。
  • 除了克雷格的好答案之外,您还可以将previous_input 初始化为read_encoder 永远不会返回的值。例如,如果read_encoder 返回一个介于 0 和 1023 之间的数字,则将 previous_input 初始化为 -1 允许代码检测到之前没有输入。
  • @DaveNewton:- 我使用 previous_input 的唯一位置是 read_input 函数内部,它需要在函数调用之间保留值

标签: c variables static


【解决方案1】:

如果你小心额外的变量,你可以

int16_t
read_input(void)
{
    static int32_t previous_input = 0;
    static int first_time = 1;

    if (first_time) {
        first_time = 0;
        previous_input = read_encoder();
    }

    // Read current_input

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;
}

更新:

如果 current_input 来自 read_encoder,这是一个清理版本,可以防止第一次重复读取。

另外,最初,我使用了一个额外的标志变量,如果有 no 超出范围的值,这是必要的。但是,我包含了第二个版本,它使用单个变量稍微快[如果不太安全]:

int16_t
read_input(void)
{
    static int32_t previous_input = 0;
    static int first_time = 0;
    int32_t current_input;

    // Read current_input
    current_input = read_encoder();

    if (first_time) {
        first_time = 0;
        previous_input = current_input;
    }

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;
}

#define OUT_OF_BOUNDS   -1

int16_t
read_input2(void)
{
    static int32_t previous_input = OUT_OF_BOUNDS;
    int32_t current_input;

    // Read current_input
    current_input = read_encoder();

    if (previous_input == OUT_OF_BOUNDS)
        previous_input = current_input;

    if (previous_input - current_input > SOME_THRESHLD)
        some_action();

    previous_input = current_input;

    // ...
}

【讨论】:

    【解决方案2】:

    您最初可以将该值设置为某个默认值,并在第一次调用该方法时检查该值是否已初始化。如果没有,则初始化它。

    int16_t read_input(void)
    {
       static int32_t previous_input = 0; // or a value indicating 'not initialised'
       if (previous_input == 0) previous_input = read_encoder();
    
       //Read current_input 
    
       if (previous_input - current_input > SOME_THRESHLD)
           some_action();
    
       previous_input - current_input;
    }
    

    【讨论】:

    • 将previous_input 保留为指示“未初始化”的值将解决我的问题。但我还有一个问题,此时并不重要——如果previous_input 存储的值是-SOME_LIMIT 到+SOME_LIMIT 会怎样。例如,它连接到一个连续旋转的旋转编码器。在这种情况下,SOME_LIMIT 值由存储该值的数据类型决定,并且仅在超出数据类型限制时才会溢出。
    【解决方案3】:

    有没有办法在函数中声明一个静态变量并将其初始化为类似于上面给出的示例的值?

    我看到了另一个问题,并提出了解决这两个问题的想法。

    减法中的溢出

    if (previous_input - current_input > SOME_THRESHLD)  // OF possible
    

    鉴于previous_input, current_input 可以独立地为 232 中的任何一个,差异有大约 233 个不同的结果。使用 int 作为 32 位,代码可能会溢出 (UB) 并且无法唯一区分。在具有 64 位 int 的特殊平台上,可以很好地计算差异,但现在功能与 32 位平台不同。

    考虑使用 int64_t,因为需要 33 位以上的数学运算。

    #define SPECIAL_BIG (INT64_MAX/2)
    static int64_t previous_input = SPECIAL_BIG;
    if (previous_input == SPECIAL_BIG) {
       previous_input = read_encoder();  // first time
    }
    ...
    if (previous_input - current_input > SOME_THRESHLD) {
        some_action();
      }
    }
    ...
    if (previous_input - current_input > SOME_THRESHLD)  // OF not possible
    

    另一方面,如果不是所有 232 组合都是可能的,并且减法和比较非常适合 32 位数学,则使用保留值。 @user3386109 并简单检测到执行初始化。

    static int32_t previous_input = SPECIAL.
    if (previous_input == SPECIAL) {
      previous_input = read_encoder();  // first time
    }
    

    我喜欢其他人建议的 static 单独标志的想法。但想提供另一种方法。

    IAC,代码,一般来说,需要previous_input - current_input的OF保护

    【讨论】:

    • 您可能想补充一点,可能溢出的原因是这些是有符号整数。
    • @GermanNerd 我基本同意。然而,如果类型是有符号或无符号整数,则存在 数学 溢出的可能性。当然,未签名的 OF 不会产生 UB,但 previous_input - current_input &gt; SOME_THRESHLD 的错误答案是数学上的。
    • 是的,我知道这一点。我只是认为 OP 可能无法理解为什么会发生这些溢出,以及后果是什么。我想不是每个人都容易理解为什么 INT32_MIN - INT32_MAX 正如你所说的那样需要 33 位数学。
    猜你喜欢
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多