[英]Are macros for large switch statements faster than functions with large switch statements?
因此,对于内联函数(1-2条语句)和小宏,似乎在使用宏或内联函数之间没有太大的性能差异。
但是,鉴于较大函数的函数调用开销,我想知道,
将大型宏用于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;
}
结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.