繁体   English   中英

大型switch语句的宏是否比大型switch语句的函数快?

[英]Are macros for large switch statements faster than functions with large switch statements?

因此,对于内联函数(1-2条语句)和小宏,似乎在使用宏或内联函数之间没有太大的性能差异。

但是,鉴于较大函数的函数调用开销,我想知道,

  • GCC 7.0
  • C语言(不是C ++)
  • OSX(不确定跨平台的差异是否很大)

将大型宏用于switch语句是否比将它们放入等效函数调用中更快? 在我这方面,假设不会内联这么大的功能。 这是我的示例代码。

#define LEX_CHAR(chPtr, tag) switch(*chPtr) { \
    case 'a':\
    case 'b':\
    case 'c':\
    case 'e':\
    case '$': tag = Tag_A;\
              break; \
    case '0':\
    case '1':\
    case '2':\
    case '3': tag = Tag_B;\
             break;\
    case 'r':\
          if(chPtr[1] == 'd' || chPtr[1] == '@') tag = Tag_c;\
          else tag = Tag_B;\
          break;\
    case '+':\
    case '#':\
    case '!':\
         if(chPtr[1] == 'd') tag = Tag_C;\
    case '-':\
    case '^':\
            tag = Tag_D;\
            break;\
    default:\
            tag = Tag_B;\
}

enum Tag
{
  Tag_A,
  Tag_B,
  Tag_C,
  Tag_D
};

typedef enum Tag Tag;


void Lex_Char(char* chPtr, Tag* tag)
{
switch(*chPtr) { 
    case 'a':
    case 'b':
    case 'c':
    case 'e':
    case '$': *tag = Tag_A;
              break; 
    case '0':
    case '1':
    case '2':
    case '3': *tag = Tag_B;
             break;
    case 'r':
          if(chPtr[1] == 'd' || chPtr[1] == '@') *tag = Tag_C;
          else *tag = Tag_B;
          break;
    case '+':
    case '#':
    case '!':
         if(chPtr[1] == 'd') *tag = Tag_C;
    case '-':
    case '^':
            *tag = Tag_D;
            break;
    default:
            *tag = Tag_B;
     }  
}

那么在宏和函数这两者之间,在函数上使用宏是否有任何优化?

首先,请注意,当宏中包含代码时,编译器必须将其内联插入到调用代码中。 当您将其设为函数时,编译器可能会内联插入它。

您还应该了解在声明如下函数时会发生什么:

void Lex_Char(char* chPtr, Tag* tag) { ... }

这告诉编译器可以从其他C文件访问该功能-编译器必须制作此功能的完整版本。 内联函数将意味着制作两个代码副本-一个用于完整功能版本,另一个在调用站点内联。 除非您的优化设置非常强调大小而不是速度,否则编译器将不愿这样做。

如果仅在当前翻译单元中使用功能,则应将其标记为“静态”:

static void Lex_Char(char* chPtr, Tag* tag) { ... }

这告诉编译器从外部无法访问它。 如果该函数在当前模块中仅使用过一次,则编译器可以愉快地内联它-这样做是“免费的”。

您还可以将函数标记为“静态内联”,从而向编译器提示您希望将其内联。

当然,这全部取决于为编译器启用优化-如果您不启用优化,则所有时间测试都是毫无用处的。

内联静态函数总是比宏更好的选择(当您可以选择时-宏比内联函数更灵活)。 该代码更容易编写,并且具有更好的静态警告和错误检查。 结果代码(假设优化)将相同。

顺便说一下,您的时序测试在这里没有意义-内联并且启用优化后,编译器将看到所涉及的值不会更改,并且不会多次运行该函数。 它可能根本不运行它,但是会在编译时预先计算结果。

哦,您忘记了“!”情况下的“中断”。

因此,经过定时测试后发现,并在相同的for循环下重复执行,宏版本的速度大约是常规函数的两倍。

这是我完整的计时器和完整的文件,可以生成结果

#include "stdio.h"
#include "stdlib.h"
#include "time.h"



#define LEX_CHAR(chPtr, tag) switch(*chPtr) { \
    case 'a':\
    case 'b':\
    case 'c':\
    case 'e':\
    case '$': tag = Tag_A;\
              break; \
    case '0':\
    case '1':\
    case '2':\
    case '3': tag = Tag_B;\
             break;\
    case 'r':\
          if(chPtr[1] == 'd' || chPtr[1] == '@') tag = Tag_C;\
          else tag = Tag_B;\
          break;\
    case '+':\
    case '#':\
    case '!':\
         if(chPtr[1] == 'd') tag = Tag_C;\
    case '-':\
    case '^':\
            tag = Tag_D;\
            break;\
    default:\
            tag = Tag_B;\
}

enum Tag
{
  Tag_A,
  Tag_B,
  Tag_C,
  Tag_D
};

typedef enum Tag Tag;


void Lex_Char(char* chPtr, Tag* tag)
{
switch(*chPtr) { 
    case 'a':
    case 'b':
    case 'c':
    case 'e':
    case '$': *tag = Tag_A;
              break; 
    case '0':
    case '1':
    case '2':
    case '3': *tag = Tag_B;
             break;
    case 'r':
          if(chPtr[1] == 'd' || chPtr[1] == '@') *tag = Tag_C;
          else *tag = Tag_B;
          break;
    case '+':
    case '#':
    case '!':
         if(chPtr[1] == 'd') *tag = Tag_C;
    case '-':
    case '^':
            *tag = Tag_D;
            break;
    default:
            *tag = Tag_B;
     }  
}




int main(){
    Tag tagPnt = Tag_D;
    char* code = "#he";

    clock_t start, end;


    start = clock();

    //for(size_t i = 0; i<10000;i++) Lex_Char(code, &tagPnt); Number of seconds: 0.000067
    for(size_t i = 0; i<10000;i++) LEX_CHAR(code, tagPnt); // Number of seconds: 0.000032

    end = clock();
    printf( "Number of seconds: %f\n", (end-start)/(double)CLOCKS_PER_SEC );
    printf("%d is tag\n", tagPnt);


    return 0;
}

结果:

  • 功能:0.000067
  • 宏:0.000032

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM