如何检查C中不同功能的调用顺序

时间:2018-08-08 05:50:27

标签: c

为了将某个变量(MyVariable)设置为“ TRUE”,我必须检查系统中是否遵守了特定的函数调用顺序。 例如,我在系统中具有不同的功能:

uint8 myFunction1()
{
    if (...)
    {
    return NOT_OK
    }
    else     
    {
    return OK
    }
}

uint8 myFunction2()
{
    if (...)
    {
    return NOT_OK
    }
    else     
    {
    return OK
    }
}


uint8 myFunction3()
{
    if (...)
    {
    return NOT_OK
    }
    else     
    {
    return OK
    }
}

MyVariable = TRUE仅在以下情况下:

  1. 确定== myFunction1

  2. 确定== myFunction2

  3. 确定== myFunction3

正是这个电话命令得到遵守。 如何在C中检查呼叫顺序却又不触碰功能主体(例如设置一些标志等)?

我仍然是初学者,正在尝试C:)

谢谢!

2 个答案:

答案 0 :(得分:1)

这几乎肯定是“ XY问题”。也就是说,您认为保存调用顺序是解决您实际问题的方法,但是您实际的问题可能是要确保首先不要以错误的顺序调用函数。

因此解决此问题的最正确方法是重新设计程序。有人提到状态机是一种解决方案。另一种解决方案可能是类似函数指针数组(这是状态机的常见实现)。


话虽这么说,您可以做一些人为的跟踪呼叫顺序的操作,尽管我并不推荐这样做。示例:

#define CALL_ORDER_N 3

const char* call_order [CALL_ORDER_N] = {NULL};
size_t call_order_i = 0;


static void save_call (const char* func)
{
  call_order[call_order_i] = func;
  call_order_i++;
  if(call_order_i == CALL_ORDER_N)
  {
    call_order_i = 0;
  } 
}

call_order会将最后3个函数调用保存为指向字符串文字的指针。函数save_call通过从每个函数传递__func__常量来更新此数组。保证__func__static const char[]一样工作,所以这是安全的。您将执行以下操作:

void myFunction1 (void)
{
  save_call(__func__);
  ...
}

void myFunction2 (void)
{
  save_call(__func__);
  ...
}

void myFunction3 (void)
{
  save_call(__func__);
  ...
}

然后遍历电话以查看它们的顺序是否正确:

static bool is_call_order_ok (void)
{
  const char* expected_order [CALL_ORDER_N] = 
  {
    "myFunction1",
    "myFunction2",
    "myFunction3"
  };

  size_t co_i = call_order_i;

  for(size_t i=0; i<CALL_ORDER_N; i++)
  {
    if(strcmp(call_order[co_i], expected_order[i])==0)
    {
      co_i++;
      if(co_i == CALL_ORDER_N)
      {
        co_i = 0;
      } 
    }
    else
    {
      return false;
    }
  }

  return true;
}

完整示例:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define CALL_ORDER_N 3

const char* call_order [CALL_ORDER_N] = {NULL};
size_t call_order_i = 0;


static void save_call (const char* func)
{
  call_order[call_order_i] = func;
  call_order_i++;
  if(call_order_i == CALL_ORDER_N)
  {
    call_order_i = 0;
  } 
}

static bool is_call_order_ok (void)
{
  const char* expected_order [CALL_ORDER_N] = 
  {
    "myFunction1",
    "myFunction2",
    "myFunction3"
  };

  size_t co_i = call_order_i;

  for(size_t i=0; i<CALL_ORDER_N; i++)
  {
    if(strcmp(call_order[co_i], expected_order[i])==0)
    {
      co_i++;
      if(co_i == CALL_ORDER_N)
      {
        co_i = 0;
      } 
    }
    else
    {
      return false;
    }
  }

  return true;
}


void myFunction1 (void)
{
  save_call(__func__);
}


void myFunction2 (void)
{
  save_call(__func__);
}


void myFunction3 (void)
{
  save_call(__func__);
}



int main (void)
{
  printf("Call 1,2,3: ");
  myFunction1();
  myFunction2();
  myFunction3();
  printf(is_call_order_ok() ? "Ok\n" : "Failed\n");

  printf("Call 3,2,1: ");
  myFunction3();
  myFunction2();
  myFunction1();
  printf(is_call_order_ok() ? "Ok\n" : "Failed\n");

  printf("Call 1,1,1: ");
  myFunction1();
  myFunction1();
  myFunction1();
  printf(is_call_order_ok() ? "Ok\n" : "Failed\n");

  return 0;
}

上述的高级,更专业的版本是将具有单个功能的mini-API组合在一起,以便为每个单个变量提供私有封装。函数save_call将成为一个多功能函数,可用于注册预期的调用顺序,保存函数调用以及验证当前的注册顺序是否正确。

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define CALL_ORDER_N 3

static bool save_call (const char* func, bool verify)
{
  bool result;

  static const char* call_order [CALL_ORDER_N] = {NULL};
  static size_t call_order_i = 0;
  static const char* expected_order [CALL_ORDER_N] = {NULL};

  size_t i = call_order_i;

  if(verify)                           // special case, verify the order
  {
    for(size_t expected=0; expected<CALL_ORDER_N; expected++)
    {
      if(call_order[i] == expected_order[expected])
      {
        i++;
        if(i == CALL_ORDER_N)
        {
          i = 0;
        } 
      }
      else
      {
        return false;
      }
    }
    return true;
  }

  if(expected_order[i] == NULL)        // register order of calls
  {
    expected_order[i] = func;
    result = true;
  }
  else                                 // save calls
  {
    call_order[i] = func;
    result = false;
  }

  call_order_i++;
  if(call_order_i == CALL_ORDER_N)
  {
    call_order_i = 0;
  } 

  return result;
}


void myFunction1 (void)
{
  if(save_call(__func__, false))
    return ;
  printf("Execute stuff in %s.\n", __func__);
}


void myFunction2 (void)
{
  if(save_call(__func__, false))
    return ;
  printf("Execute stuff in %s.\n", __func__);
}


void myFunction3 (void)
{
  if(save_call(__func__, false))
    return ;
  printf("Execute stuff in %s.\n", __func__);
}



int main (void)
{
  /* register call order: */
  myFunction1();
  myFunction2();
  myFunction3();


  printf("Call 1,2,3:\n");
  myFunction1();
  myFunction2();
  myFunction3();
  printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");

  printf("Call 3,2,1:\n");
  myFunction3();
  myFunction2();
  myFunction1();
  printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");

  printf("Call 1,1,1:\n");
  myFunction1();
  myFunction1();
  myFunction1();
  printf(save_call(NULL, true) ? "Ok\n\n" : "Failed\n\n");

  return 0;
}

save_call当然应该正确放置在自己的.h / .c文件对中。

答案 1 :(得分:0)

没有直接且可移植的方法。话虽这么说,调试器非常擅长在达到某个功能时中断执行流程,所以您可以使用调试器,也可以在调用函数时使用调试功能来发出警告(不幸的是,这里没有可移植的内容)。

或者,某些链接器允许隐藏一些标识符并替换它们,因此使用自定义(和高级)链接选项可以将对这些函数的所有调用替换为对自定义包装器的调用。但这又只对特定的实现有意义,因此也不是C语言。

无论如何,这是一个不常见的要求,我无法想象其背后的实际原因。也许您可以为您的实际问题提供更多背景信息...