最后更新于 .

由于python语法的简洁,所以在写c代码的时候,有时候也会想能不能把C代码写的更简练一点,这几天遇到一个,给大家分享一下。 比如我们要用C写一个判断语句,然后根据不同的值返回不同的内容。

if(1 == val)
{
    return "this is one";
}
else if(2 == val)
{
    return "this is two";
}
else if(3 == val)
{
    return "this is three";
}

如果判断的逻辑很多,代码就会显得很臃肿(文中的例子用switch也可以,但是也还是很难看),如果用python,就会这样写(为了和C类比,这里没有用字典):

datas = [
(1,"this is one"),(2,"this is two"),(3,"this is three")
]
for v in datas:
    if v[0] == val:
        return v[1]

那在c里面是否能同样的方法实现呢,是可以的:

struct
{
    int key;
    string strdata;
}arr_datas[]={
    {1,"this is one"},
    {2,"this is two"},
    {3,"this is three"},
};
for (i = 0; i < 3; i++)
{
    if (arr_datas[i].key == val)
    {
        return arr_datas[i].strdata;
    }
}

附: 有人可能想到用stl的map,查找速度会快一些,不过想到定义一个map,然后调用一堆insert其实也挺麻烦的,而且例子中用的是int,但是并不是所有的类型都是可hash的,所以有些情况下map并不能胜任。

Pingbacks

Pingbacks已打开。

Trackbacks

引用地址

评论

  1. miles

    miles on #

    我觉得还不如原来的写法呢。。。

    Reply

    1. Dante

      Dante on #

      呃,这个。。。你可以想想一下有10个返回码,分别要来返回不同的值。。
      就需要写10个if else,而且很不容易维护。

      Reply

      1. miles

        miles on #

        好吧。。。。

        Reply

  2. Pinepara

    Pinepara on #

    这是一种很常用的设计模式,有一个名字叫做 “table-driven”——表驱动法

    Reply

    1. Dante

      Dante on #

      原来如此,在python里面经常这样写,不知道原来还有这样一个定义。

      Reply

      1. Pinepara

        Pinepara on #

        《Code Complete》(代码大全)里面有详细的介绍

        Reply

        1. Dante

          Dante on #

          看来有必要好好读一下。。一直放在硬盘里。。

          Reply

          1. madper

            madper on #

            lisp常用表驱动法的...抽空看看sicp应该也挺好的, 虽然我没看这本...

            Reply

  3. dormouse

    dormouse on #

    这样的比较有什么实际用途吗?Python是不是用C写出的?如果是,那么Python的任何用法都可以用C来实现。盘古开天据说用的是C,你信不:-》

    Reply

    1. Dante

      Dante on #

      呵呵,言重了,我python和C都用,还用php,只是个人喜好而已~ 大家选择自己喜欢的就行~

      Reply

  4. lihex

    lihex on #

    用map我会这么写,光初始化就很麻烦,呵呵
    map amap;
    string str[3]={"333","222","444"}
    int i=0;
    while(i&lt;3)
    {
    amap[i]=str[i++];

    }

    Reply

  5. greatghoul

    greatghoul on #

    除了维护外,语法和逻辑上似乎都变复杂了。这种写法可不可取,还得两说。

    如果情况比较少,感觉没有必要这么折腾,如果情况比较多,这么多重复的事,干嘛不写成函数。

    我个人觉得没有必要为了简化而简化。用爱因思坦那货的话来说"Make everything as simple as possible, but not simpler." 过犹不及

    Reply

    1. Dante

      Dante on #

      这是我用这个方法写的统计时间段的函数:
      string get_maptime(int time_ms)
      {
      struct
      {
      int iTime;
      string strTimeKey;
      }arr_times[]={
      {5,"[0,5]"},
      {10,"(5,10]"},
      {50,"(10,50]"},
      {100,"(50,100]"},
      {200,"(100,200]"},
      {500,"(200,500]"},
      {1000,"(500,1000]"},
      {-1,"(1000,~)"},
      };
      int count = sizeof(arr_times) / sizeof(arr_times[0]);

      for (int i = 0; i < count; i++)
      {
      if (arr_times[i].iTime == -1 || time_ms <= arr_times[i].iTime)
      {
      return arr_times[i].strTimeKey;
      }
      }
      return "(1000,~)";//实际上到不了这一步
      }

      Reply

    2. madper

      madper on #

      逻辑上会变得比较简单吧, 如果是老一辈的程序员, 应该会很喜欢表驱动的方法.

      Reply

  6. iCyOMiK

    iCyOMiK on #

    谢谢,分享,不错。

    Reply

  7. osily

    osily on #

    如果val只是从1到n这样的,一个元组就可以了,如果不是显然用字典好些,不然凭空提到复杂度,代码也不简洁。
    c中也是,应该先考虑数组。其实这总情况用switch就很正常的,没人会说用switch臃肿。
    c++中除了数组,map可以应对更多情况。stl里的map不是用hash实现的,而是红黑树,是基于比较排序的。而python的map是用hash实现的。

    Reply

    1. Dante

      Dante on #

      这是我用这个方法写的统计时间段的函数:
      string get_maptime(int time_ms)
      {
      struct
      {
      int iTime;
      string strTimeKey;
      }arr_times[]={
      {5,”[0,5]“},
      {10,”(5,10]”},
      {50,”(10,50]”},
      {100,”(50,100]”},
      {200,”(100,200]”},
      {500,”(200,500]”},
      {1000,”(500,1000]”},
      {-1,”(1000,~)”},
      };
      int count = sizeof(arr_times) / sizeof(arr_times[0]);

      for (int i = 0; i < count; i++)
      {
      if (arr_times[i].iTime == -1 || time_ms <= arr_times[i].iTime)
      {
      return arr_times[i].strTimeKey;
      }
      }
      return “(1000,~)”;//实际上到不了这一步
      }

      其实主要是因为这个函数而写了这篇文章,可能文中的例子没有举好,让大家偏向map进行讨论了

      Reply

  8. fleurer

    fleurer on #

    喜欢这种写法。似乎在minix的源码里见过这种风格

    Reply

    1. Dante

      Dante on #

      哈哈,同好~

      Reply

  9. 雨忆

    雨忆 on #

    可以用jump table 来代替switch吧。
    table driven 法?

    Reply

    1. Dante

      Dante on #

      咱俩其实一个意思,呵呵~

      Reply

  10. Nona Mills

    Nona Mills on #

    喜欢这种写法。似乎在minix的源码里见过这种风格

    Reply

  11. Barbara Chavez

    Barbara Chavez on #

    这是我用这个方法写的统计时间段的函数: string get_maptime(int time_ms) { struct { int iTime; string strTimeKey; }arr_times[]={ {5,"[0,5]"}, {10,"(5,10]"}, {50,"(10,50]"}, {100,"(50,100]"}, {200,"(100,200]"}, {500,"(200,500]"}, {1000,"(500,1000]"}, {-1,"(1000,~)"}, }; int count = sizeof(arr_times) / sizeof(arr_times[0]); for (int i = 0; i &lt; count; i++) { if (arr_times[i].iTime == -1 || time_ms &lt;= arr_times[i].iTime) { return arr_times[i].strTimeKey; } } return &quot;(1000,~)&quot;;//实际上到不了这一步 }

    Reply

  12. Keisha Carver

    Keisha Carver on #

    看来有必要好好读一下。。一直放在硬盘里。。

    Reply

  13. 刺猬

    刺猬 on #

    这个实例比较简单,如果有很多case的话用表驱动法更清晰一些。
    不过对于只有几种情况的case,if-else我觉得更清晰

    Reply

    1. Dante

      Dante on #

      哈哈,同感!~

      Reply

  14. zap

    zap on #

    if或者switch的方法虽然代码比较繁琐,但是执行效率和代码体积都有优势,对嵌入式c来说,这个是更关键的。

    Reply

  15. 李立强

    李立强 on #

    其实可以这样
    char *print[] = {"this is one", "this is two", "this is three"}
    return print[val-1]; //或者加一项空串,然后就不用减去1了

    Reply

    1. Dante

      Dante on #

      呃。。不是想实现数组。。只是文中的例子数字恰好是连续的。。

      Reply

      1. 李立强

        李立强 on #

        那就做个转移表啊,用一个函数来返回下标,虽然效果差不多的但是看代码就爽多了,这两个方法我都是从《C和指针》中学的

        Reply

  16. null

    null on #

    struct
    {
    int key;
    string strdata;
    }arr_datas[]={
    {1,"this is one"},
    {2,"this is two"},
    {3,"this is three"},
    };
    if (val&gt;0 &amp;&amp; val&lt;4)
    return arr_datas[val].strdata;

    这样不是省去了for循环了.

    Reply

    1. arthur

      arthur on #

      如果传入的所以不是简单的自然数,可不是随便比较一下的问题。

      如果
      typedef enum{

      S_A = 178 &lt;&lt;16 | 1,
      S_B = 178 &lt;&lt; 16 | 2
      ....
      S_C= 192 &lt;&lt; 16 | 1,
      S_D = 192 &lt;&lt; 16 |2,
      ...
      }e_idx;

      void get _value(e_idx idx)
      {
      if (idx == S_A)
      printf(...);
      else if (...)

      }
      试问,有简单的方法吗?加入enum有好几百,这个if就要好几百,可见用if会疯掉,用case可能更好,但是用table好解决吗? 呵呵

      Reply

  17. endle

    endle on #

    为啥我觉得 switch 搭配 define 和 enum 更简洁?

    Reply

  18. sarrow104

    sarrow104 on #

    其实“表驱动”只不过是“数据驱动”的前奏。

    这是把逻辑用数据来表现的需求。

    内嵌的脚步语言,也属于“表驱动”。一点小见解。

    Reply

发表评论