我分叉了一个 C++ 项目并在 switch 中添加了一些案例。然后它会跳转到下一个案例的中间。条件为
int
,案例值为 #define
d。由于代码很大,我在这里写一些等效且简单的内容:
#define AAA 1
#define BBB 2
int X::func(int i) {
bool b = (i == 5);
int v = (b ? 10 : 5);
switch (i) {
case AAA:
if (b && v > 4) {
v = v + 1;
return 0;
}
break;
case BBB:
if (!b || v > 40) {
v = v + 2;
b = false; // direct jump here from the switch for i = AAA
return 0;
}
break;
}
return -1;
}
如果我将 AAA 传递给 X::func,则代码执行会直接从 BBB 案例内的
switch
跳转到 b = false;
。在真实的代码中,我有几十种情况,而且它发生在中间。如果我完全评论case BBB
,它会跳到评论中的同一位置!每个 case 都以 break;
结尾,并且内部没有变量声明。就像这里的变量 b 和 v 一样,它们是在 switch 语句之前声明的。
部分案例位于
#ifdef
#endif
区块中。发生问题的其他情况都在这个块中。条件为真,因此该块已编译。无论如何,我在抑制这两个预编译器语句后测试了它,它是一样的。
如果我添加括号
{}
来完全包容像这里这样的情况,我仍然会得到相同的结果:
case BBB: {
if (!b || v > 40) {
v = v + 2;
b = false; // direct jump here from the switch for i = AAA
return 0;
}
break;
}
无论是在调试会话中还是在正常执行中,一切都可以正常编译并执行相同的操作。我在 Eclipse CDT Indigo 下使用 gcc 4.5.4。
看起来像是编译器错误,但原因可能是什么?
如果您通过调试器单步执行该函数,那么调试器中的“当前突出显示的行”不一定对应于当前正在执行的行(当涉及循环时、当打开优化时、当有大量宏时等)。
切换后将变量打印到 stdout/stderr 并查看它们的值是否正确。还可以在
cases
中将一些调试行打印到 stdout/stderr。如果您得到的输出是正确的,请停止担心奇怪的代码执行顺序。
示例:
#define AAA 1
#define BBB 2
int X::func(int i) {
bool b = (i == 5);
int v = (b ? 10 : 5);
std::cout << "before switch/case" << std::endl;
switch (i) {
case AAA:
std::cout << "AAA, before if block" << std::endl;
if (b && v > 4) {
v = v + 1;
std::cout << "within AAA if block" << std::endl;
return 0;
}
std::cout << "AAA, after if block" << std::endl;
break;
case BBB:
std::cout << "BBB, before if block" << std::endl;
if (!b || v > 40) {
v = v + 2;
b = false; // direct jump here from the switch for i = AAA
std::cout << "BBB, within if block" << std::endl;
return 0;
}
std::cout << "BBB, after if block" << std::endl;
break;
}
std::cout << "after switch/case" << std::endl;
return -1;
}
--编辑--
如果为 case 语句添加 {} 括号可能会有所帮助:
case AAA:{
break;
}
如果您将案例中的内容转移到单独的功能中,这肯定会有所帮助。这不会改进代码,但调试器肯定能够遍历它们。
我已经从原始项目(项目)构建了一个“克隆”项目(项目测试)。在预构建步骤中,我有一个 rsync 来复制所有源文件(重点是不要复制自动工具的内容):
rsync -a --exclude=tests/* --exclude=perf/* --exclude=tools/* --include=*/ --include=*.[ch] --include=*.[ch]pp --exclude=* ${workspace_loc:/project}/ ${workspace_loc:/project_test}/ && cp ${workspace_loc:/project}/tests/one_with_main.cpp ${workspace_loc:/project_test}/tests/
构建良好,调试符合预期。
替代方案可以是
rsync -a --delete
而不是 rsync -a
。