因此,对于内联函数(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;
}
}
所以在这两者之间,宏和函数,在函数上使用宏有什么优化吗?
答案 0 :(得分:1)
首先,请注意,当您在宏中有代码时,编译器必须在调用代码中内嵌它。当您将其设为函数时,编译器可以将其插入内联。
您还应该了解在声明如下函数时会发生什么:
void Lex_Char(char* chPtr, Tag* tag) { ... }
这告诉编译器可以从其他C文件访问该函数 - 编译器必须创建此函数的完整版本。内联函数将意味着制作两个代码副本 - 一个用于完整功能版本,另一个在调用站点内联。编译器将不愿意这样做,除非您的优化设置强调大小超速。
如果只在当前翻译单元中使用某个功能,则应将其标记为“静态”:
static void Lex_Char(char* chPtr, Tag* tag) { ... }
这告诉编译器它无法从外部访问。如果该函数只在当前模块中使用过一次,那么编译器可以愉快地内联它 - 这样做是“免费的”。
您还可以将该函数标记为“静态内联”,为编译器提供一个暗示您热衷于内联的提示。
当然,这一切都取决于是否为编译器启用了优化 - 如果您不启用优化,那么您所有的时间测试都毫无价值。
内联静态函数总是比宏更好的选择(当你有选择时 - 宏可以比内联函数更灵活)。代码更清晰,您可以更好地进行静态警告和错误检查。结果代码(假设优化)将是相同的。
顺便提一下,你的时序测试在这里毫无意义 - 编译器会看到所涉及的值不会改变,并且在内联并启用优化时不会多次运行该函数。它可能根本不运行,但在编译时预先计算结果。
哦,你忘了案件中的“休息”'!'。
答案 1 :(得分:0)
因此,经过定时测试后,在相同的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;
}
<强>结果:强>