【问题标题】:C code - need to clarify the effectivenessC代码 - 需要阐明有效性
【发布时间】:2009-10-09 05:52:08
【问题描述】:

您好,我已经根据需求编写了代码。

(field1_6)(field2_30)(field3_16)(field4_16)(field5_1)(field6_6)(field7_2)(field8_1 )..... 这是一个桶(8 个字段)的数据。我们一次将收到 20 个桶,这意味着总共 160 个字段。 我需要根据预定义的条件取 field3、field7 和 fields8 的值。 如果输入参数为 N,则从第一个存储桶中获取三个字段,如果是 Y,我需要 从除第一个以外的任何其他存储桶中获取三个字段。 如果 argumnet 是 Y,那么我需要一个接一个地扫描所有 20 个存储桶并检查 桶的第一个字段不等于 0,如果为真,则获取该桶的三个字段并退出。 我已经编写了代码并且它也可以正常工作..但不太相信它是有效的。 我害怕有时会崩溃。请建议下面是代码。

int CMI9_auxc_parse_balance_info(char *i_balance_info,char  *i_use_balance_ind,char *o_balance,char *o_balance_change,char *o_balance_sign
)
{
  char *pch = NULL;
  char *balance_id[MAX_BUCKETS] = {NULL};
  char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
  char *str[160] = {NULL};
  int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
  int total_bukets ;
  memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
  memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
  //balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0';
  pch = strtok (balance_info,"*");
  while (pch != NULL && i < 160)
  {
     str[i]=(char*)malloc(strlen(pch) + 1);
     strcpy(str[i],pch);
     pch = strtok (NULL, "*");
     i++;
  }
total_bukets  = i/8  ;
  for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
  {
  balance_id[j]=str[b_id];
  b_id=b_id+8;
  }
  if (!memcmp(i_use_balance_ind,"Y",1))
  {
     if (atoi(balance_id[0])==1)
     {
        memcpy(o_balance,str[2],16);
        memcpy(o_balance_change,str[3],16);
        memcpy(o_balance_sign,str[7],1);
        for(i=0;i<160;i++)
        free(str[i]);
        return 1;
     }
     else
     {
        for(i=0;i<160;i++)
        free(str[i]);
      return 0;
     }
  }
  else if (!memcmp(i_use_balance_ind,"N",1))
  {
      for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
      {
        b_ind=(j*8)+2;
        bc_ind=(j*8)+3;
        bs_ind=(j*8)+7;
       if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
       {
        memcpy(o_balance,str[b_ind],16);
        memcpy(o_balance_change,str[bc_ind],16);
        memcpy(o_balance_sign,str[bs_ind],1);
        for(i=0;i<160;i++)
        free(str[i]);
        return 1;
       }
      }
     for(i=0;i<160;i++)
     free(str[i]);
    return 0;
  }
 for(i=0;i<160;i++)
 free(str[i]);
return 0;
}

【问题讨论】:

    标签: c++ c unix gdb dbx


    【解决方案1】:

    我的感觉是这段代码很脆弱。如果输入良好(我不建议为您进行桌面检查),它可能会很好地工作,但如果输入不正确,它会崩溃并烧毁或给出误导性结果。

    您是否测试过意外输入?例如:

    • 假设 i_balance_info 为空?
    • 假设 i_balance_info 是 ""?
    • 假设输入字符串中的项少于 8 个,这行代码会做什么?

      memcpy(o_balance_sign,str[7],1);
      
    • 假设 str[3] 中的 item 长度小于 16 个字符,这行代码会做什么?

      memcpy(o_balance_change,str[3],16);
      

    我编写此类代码的方法是防止所有此类可能性。至少我会添加 ASSERT() 语句,我通常会编写显式输入验证并在错误时返回错误。这里的问题是界面似乎不允许任何可能有错误输入的可能性。

    【讨论】:

    • @dgna,第一件事是我确认我永远不会在单个存储桶中收到少于 8 个字段。唯一的问题是有时我可能不会收到 20 个桶
    • 代码的本质是它可以在新的上下文和新的假设下重用。防御性编码可以保护您免受呼叫您的事物的更改(和错误)。如果您担心性能开销,请使用 ASSERT(),它可以在开发期间使用并编译出来用于生产
    【解决方案2】:

    我很难阅读您的代码,但 FWIW 我已经添加了一些 cmets,HTH:

    // do shorter functions, long functions are harder to follow and make errors harder to spot
    // document all your variables, at the very least your function parameters
    // also what the function is suppose to do and what it expects as input
    int CMI9_auxc_parse_balance_info
    (
      char *i_balance_info,
      char *i_use_balance_ind,
      char *o_balance,
      char *o_balance_change,
      char *o_balance_sign
    )
    {
      char *balance_id[MAX_BUCKETS] = {NULL};
      char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
      char *str[160] = {NULL};
      int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
      int total_bukets=0; // good practice to initialize all variables
    
      //
      // check for null pointers in your arguments, and do sanity checks for any
      // calculations
      // also move variable declarations to just before they are needed
      //
    
      memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
      memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
      //balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0';  // should be BALANCE_INFO_FIELD_MAX_LENTH-1
    
      char *pch = strtok (balance_info,"*"); // this will potentially crash since no ending \0
    
      while (pch != NULL && i < 160)
      {
        str[i]=(char*)malloc(strlen(pch) + 1);
        strcpy(str[i],pch);
        pch = strtok (NULL, "*");
        i++;
      }
      total_bukets  = i/8  ;
      // you have declared char*str[160] check if enough b_id < 160
      // asserts are helpful if nothing else assert( b_id < 160 );
      for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
      {
        balance_id[j]=str[b_id];
        b_id=b_id+8;
      }
      // don't use memcmp, if ('y'==i_use_balance_ind[0]) is better
      if (!memcmp(i_use_balance_ind,"Y",1))
      {
        // atoi needs balance_id str to end with \0 has it?
        if (atoi(balance_id[0])==1)
        {
          // length assumptions and memcpy when its only one byte
          memcpy(o_balance,str[2],16);
          memcpy(o_balance_change,str[3],16);
          memcpy(o_balance_sign,str[7],1);
          for(i=0;i<160;i++)
            free(str[i]);
          return 1;
        }
        else
        {
          for(i=0;i<160;i++)
            free(str[i]);
          return 0;
        }
      }
      // if ('N'==i_use_balance_ind[0]) 
      else if (!memcmp(i_use_balance_ind,"N",1))
      {
        // here I get a headache, this looks just at first glance risky. 
        for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
        {
          b_ind=(j*8)+2;
          bc_ind=(j*8)+3;
          bs_ind=(j*8)+7;
          if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
          {
            // length assumptions and memcpy when its only one byte
            // here u assume strlen(str[b_ind])>15 including \0
            memcpy(o_balance,str[b_ind],16);
            // here u assume strlen(str[bc_ind])>15 including \0
            memcpy(o_balance_change,str[bc_ind],16);
            // here, besides length assumption you could use a simple assignment
            // since its one byte
            memcpy(o_balance_sign,str[bs_ind],1);
            // a common practice is to set pointers that are freed to NULL.
            // maybe not necessary here since u return
            for(i=0;i<160;i++)
              free(str[i]);
            return 1;
          }
        }
        // suggestion do one function that frees your pointers to avoid dupl
        for(i=0;i<160;i++)
          free(str[i]);
        return 0;
      }
      for(i=0;i<160;i++)
        free(str[i]);
      return 0;
    }
    

    当您想要访问数组中的偏移量时,一个有用的技术是创建一个映射内存布局的结构。然后你将指针转换为结构的指针,并使用结构成员来提取信息,而不是你的各种 memcpy

    我还建议您在一般情况下重新考虑函数的参数,如果将它们中的每一个都放在一个结构中,您可以更好地控制并使函数更具可读性,例如

    int foo( input* inbalance, output* outbalance )
    

    (或者你想要做的任何事情)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      • 2018-04-27
      相关资源
      最近更新 更多