【发布时间】:2020-05-23 16:13:33
【问题描述】:
在 C++ 中,我有一个包含 switch-case 语句的内联函数。我发现,当编写一些特定案例分支时,程序的时间成本会显着增加,即使在运行时从未遇到过特定案例。
此处显示了一个代码示例:
#include <stdio.h>
#include <iostream>
#include <sys/time.h>
#include <string>
using namespace std;
enum Types {
T0 = 0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TS, TA, TB, TC
};
int64_t special(int64_t num, string str) {
char buf[16];
buf[0] = (num % 10) + '0';
buf[1] = (num % 10) + '0';
buf[2] = str.c_str()[0];
return atoi(buf);
}
inline int64_t common(int64_t base, int64_t num) {
return num + base;
}
inline int64_t myfunc(Types t, int64_t num) {
string str;
switch (t) {
case T0:
return 0;
break;
#define CASE_TYPE(tv, base) \
case tv: \
return common(base, num); \
break;
CASE_TYPE(T1, 1)
CASE_TYPE(T2, 2)
CASE_TYPE(T3, 3)
CASE_TYPE(T4, 4)
CASE_TYPE(T5, 5)
CASE_TYPE(T6, 6)
CASE_TYPE(T7, 7)
CASE_TYPE(T8, 8)
CASE_TYPE(T9, 9)
#undef CASE_TYPE
case TS:
// Comment out the following 3 lines increases performance
str = string((char*)&num, 4);
return special(num, str);
break;
// Comment out the above 3 lines increases performance
case TA:
case TB:
case TC:
return 0;
break;
}
return 0;
}
static const int LoopNum = 1000000000;
static inline int64_t now() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + (int64_t)tv.tv_usec / 1000;
}
// execution command line: ./test 1 1
int main(int argc, char *argv[])
{
Types t = (Types)atoi(argv[1]); // t = T1
int64_t num = (int64_t)atoi(argv[2]); // t = 1
int64_t total = 0;
int64_t start = now();
for (int i = 0; i < LoopNum; i++) {
total += myfunc(t, num);
}
cout << "Time Cost: " << now() - start << " ms" << endl;
cout << "Result: " << total << endl;
return 0;
}
在这个程序中,当case TS块中的行被注释掉时,性能提升很多:
-
使用
case TS块:时间成本 = 2250 毫秒 -
没有
case TS块:时间成本 = 1492 毫秒
程序编译并执行命令:g++ -o test -O2 test.cpp && ./test 1 1。使用此命令,程序中的变量值为t = T1和num = 1。
在Windows Subsystem for linux (Ubuntu 18.04) 和g++ 7.4.0 上测试。
令人困惑的是,这个问题并不总是出现。我对如何编写这样的代码没有清楚的了解(但上面的例子确实出现了这个问题)。
根据我的测试,似乎在以下一些情况下会出现问题:
- 具体案例中的程序很复杂。例如。当程序包含远程进程调用时。
- 特定案例不是最后一个案例,或者案例值不是枚举中的最大值。
我真的不知道这是如何发生的以及如何避免它。任何人都可以提供任何建议吗?无论是机制还是变通方法都会有所帮助。谢谢。
【问题讨论】:
-
您的代码中至少有两个问题会导致未定义的行为。首先,您不能将整数转换为字符串;其次,您在没有显式字符串空终止符的数组上使用字符串函数。
-
@Some 程序员老兄 谢谢。但请忽略这些问题。我只想添加一些完整的逻辑来重现我的问题。正如我所提到的,由于从未执行过有关字符串的操作,因此潜在的风险不是问题。当然,这些问题在实际程序中是必须要注意的。
标签: c++ switch-statement