使用函数指针比 switch 语句慢
Using function pointers is slower than switch statement
我有这段代码用于测试 switch 语句与函数指针的行为:
#include <stdio.h>
#include <time.h>
int mySum(int startingValue)
{
return startingValue += 1;
}
int mySub(int startingValue)
{
return startingValue -= 1;
}
int main()
{
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("USING SWITCH\n");
printf("Start time: %s", asctime(timeinfo));
int startingValue = 25;
int currentOperation = 0;
// Using switch
for (long long i = 0; i < 10000000000; i++)
{
switch (currentOperation)
{
case 1:
startingValue = mySum(startingValue);
break;
case 0:
startingValue = mySub(startingValue);
break;
}
if (currentOperation)
currentOperation = 0;
else
currentOperation = 1;
}
printf("Result is: %d\n", startingValue);
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("End time: %s", asctime(timeinfo));
printf("\n\n\n");
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("USING FUNCTION POINTERS\n");
printf("Start time: %s", asctime(timeinfo));
startingValue = 25;
currentOperation = 0;
// Using function pointers
int (*mySwitchOfFunctionPointers[2])(int x);
mySwitchOfFunctionPointers[0] = &mySub;
mySwitchOfFunctionPointers[1] = &mySum;
for (long long i = 0; i < 10000000000; i++)
{
startingValue = (*mySwitchOfFunctionPointers[currentOperation])(startingValue);
if (currentOperation)
currentOperation = 0;
else
currentOperation = 1;
}
printf("Result is: %d\n", startingValue);
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("End time: %s", asctime(timeinfo));
return 0;
}
输出是这样的,所以代码使用 switch 语句立即执行,但使用函数指针需要很多秒:
USING SWITCH
Start time: Mon Oct 25 18:04:06 2021
Result is: 25
End time: Mon Oct 25 18:04:06 2021
USING FUNCTION POINTERS
Start time: Mon Oct 25 18:04:06 2021
Result is: 25
End time: Mon Oct 25 18:04:34 2021
编译为
gcc -c main.c -o test.o -O3 -Wall -Wno-unused -std=c99
gcc test.o -o test
为什么第二种方法比第一种慢???代码有问题吗?有什么想法吗?
编译器可以内联开关,然后优化器足够聪明,可以意识到您的整个循环是空操作,因此将其优化掉。
它不会对函数指针执行此操作。
参见 https://godbolt.org/z/qxxoof5cn
如果您将代码更改为编译器无法优化的代码,那么您将获得截然不同的结果。例如:
int mySum(int startingValue)
{
return startingValue += rand();
}
int mySub(int startingValue)
{
return startingValue -= rand();
}
编译器优化参数 (-O3) 是造成此行为的原因。
编译器可以优化第一个 for
-Loop,里面有 switch
,因为它有关于这段代码的所有需要的信息。
不幸的是,编译器无法优化带有函数指针的代码。由于编译器不知道调用了哪些函数。
如果你在编译时删除-O3参数,你会发现,函数指针和switch-case
语句需要相似的时间。
我有这段代码用于测试 switch 语句与函数指针的行为:
#include <stdio.h>
#include <time.h>
int mySum(int startingValue)
{
return startingValue += 1;
}
int mySub(int startingValue)
{
return startingValue -= 1;
}
int main()
{
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("USING SWITCH\n");
printf("Start time: %s", asctime(timeinfo));
int startingValue = 25;
int currentOperation = 0;
// Using switch
for (long long i = 0; i < 10000000000; i++)
{
switch (currentOperation)
{
case 1:
startingValue = mySum(startingValue);
break;
case 0:
startingValue = mySub(startingValue);
break;
}
if (currentOperation)
currentOperation = 0;
else
currentOperation = 1;
}
printf("Result is: %d\n", startingValue);
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("End time: %s", asctime(timeinfo));
printf("\n\n\n");
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("USING FUNCTION POINTERS\n");
printf("Start time: %s", asctime(timeinfo));
startingValue = 25;
currentOperation = 0;
// Using function pointers
int (*mySwitchOfFunctionPointers[2])(int x);
mySwitchOfFunctionPointers[0] = &mySub;
mySwitchOfFunctionPointers[1] = &mySum;
for (long long i = 0; i < 10000000000; i++)
{
startingValue = (*mySwitchOfFunctionPointers[currentOperation])(startingValue);
if (currentOperation)
currentOperation = 0;
else
currentOperation = 1;
}
printf("Result is: %d\n", startingValue);
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("End time: %s", asctime(timeinfo));
return 0;
}
输出是这样的,所以代码使用 switch 语句立即执行,但使用函数指针需要很多秒:
USING SWITCH
Start time: Mon Oct 25 18:04:06 2021
Result is: 25
End time: Mon Oct 25 18:04:06 2021
USING FUNCTION POINTERS
Start time: Mon Oct 25 18:04:06 2021
Result is: 25
End time: Mon Oct 25 18:04:34 2021
编译为
gcc -c main.c -o test.o -O3 -Wall -Wno-unused -std=c99
gcc test.o -o test
为什么第二种方法比第一种慢???代码有问题吗?有什么想法吗?
编译器可以内联开关,然后优化器足够聪明,可以意识到您的整个循环是空操作,因此将其优化掉。 它不会对函数指针执行此操作。 参见 https://godbolt.org/z/qxxoof5cn
如果您将代码更改为编译器无法优化的代码,那么您将获得截然不同的结果。例如:
int mySum(int startingValue)
{
return startingValue += rand();
}
int mySub(int startingValue)
{
return startingValue -= rand();
}
编译器优化参数 (-O3) 是造成此行为的原因。
编译器可以优化第一个 for
-Loop,里面有 switch
,因为它有关于这段代码的所有需要的信息。
不幸的是,编译器无法优化带有函数指针的代码。由于编译器不知道调用了哪些函数。
如果你在编译时删除-O3参数,你会发现,函数指针和switch-case
语句需要相似的时间。