我的代码中有一个关键循环:
int myloop(int a, .....){
/* some stuff */
// Critical loop
while(...){
/* Some Stuff */
if(a == 1){
// .....
}
else if(a == 2){
// .....
}
else if(a == 3){
// .....
}
else{
// ....
}
}
}
由于循环从不接触“a”的值,所采用的分支永远不会改变,但由于此循环非常重,因此需要多次测试“a”的值,这是完全没必要的。最好的事情可能是复制循环,以便在循环开始之前可以测试“if”,但是这意味着复制了两种情况常见的很多东西,并且会导致代码非常难看......
有没有办法让GCC / G ++在编译代码时复制它?或者其他任何避免多次测试价值的技巧?
感谢您的帮助!
Nathann
答案 0 :(得分:6)
首先,您可以在此处使用switch
语句:
switch(a) {
case 0:
// handle a==0
break;
case 1:
// handle a==1
break;
default:
// handle all other cases
}
此可能使编译器能够生成更快的代码,即执行单个计算跳转而不是针对a
的多次检查。
这意味着要复制两种情况共同的很多东西
<强>重构强>!将共享代码放入单独的函数中,可能会将其声明为inline
,并希望编译器遵循提示?函数内联是让编译器进行代码复制的好方法(另外两种方式是模板和预处理器,这两种方式在这里显然都不合适。)
inline void sharedStuff() {...}
int myloop(int a, .....){
/* some stuff */
if (a==1) {
while(...){
// code specific to a==1
// do shared stuff
sharedStuff();
}
}
else if ...
}
当然这取决于你在循环中做了什么,但你应该得到基本原则。
最后但并非最不重要:个人资料。检查循环是否真的是性能瓶颈。看看生成的机器代码。很可能编译器已经使用了大多数建议的优化。
答案 1 :(得分:2)
您可以使用switch
声明:
while(...)
{
switch(a)
{
case 1:
// do what you want
break;
case 2:
// do what you want
break;
case x:
// do what you want
break;
default:
//if not matching any previous..
}
}
答案 2 :(得分:2)
这样做的一种常见方法如下:
// make function implementation inline...
static inline int myloop_inline(int a, .....){
/* some stuff */
// Critical loop
while(...){
/* Some Stuff */
if(a == 1){
// .....
}
else if(a == 2){
// .....
}
else if(a == 3){
// .....
}
else{
// ....
}
}
}
// wrapper function which calls myloop_inline with hard-coded values of a
int myloop(int a, .....){
{
switch (a)
{
// expand inline function for all performance-critical values of a...
case 1:
myloop_inline(1);
break;
case 2:
myloop_inline(2);
break;
case 3:
myloop_inline(3);
break;
...
// for any values of a for which the function is not performance-critical
// we can just use a default case...
default:
myloop_inline(a);
break;
}
}
请注意,因为当a
被调用myloop_inline()
时,myloop()
作为文字常量传递,编译器可以在扩展内联函数时优化掉所有不相关的测试和死代码。< / p>
您可能希望采取措施确保myloop_inline()
实际上被内联,这包括当然启用优化的编译(例如-O3
),并且在例如__attribute__ ((always_inline))
的情况下。 gcc你可能想要添加{{1}}。
答案 3 :(得分:1)
我建议传递“a”作为模板参数,即
template< int a >
int myloop(.....) {
if( a==1 ) { ... }
}
就像那样,它会被正确地优化掉。
但是,您将无法将变量作为模板参数传递, 所以在其他地方,你必须放置那个开关。
switch(a) {
case 1: myloop<1>(...); break;
...
}
答案 4 :(得分:1)
如何定义一个函数来执行while循环中发生的任何事情并定义它inline
?然后在while
内移动if
循环并在那里调用函数。这将完全符合您的要求。
答案 5 :(得分:1)
如何使每个单独的函数,然后有一个指向函数的指针?
void func_a() {
// ...
}
void func_b() {
// ...
}
int myloop(int a, ...) {
void (*func)();
if (a == 1) {
func = &func_a;
} else if (a == 2) {
func = &func_b;
} ...
while (1) {
/* Some stuff */
func();
}
}
答案 6 :(得分:0)
int myloop(int a, ...){
if(a == 1){
myloop1(a, ...);
}
else if(a == 2){
myloop2(a, ...);
}
else if(a == 3){
myloop3(a, ...);
}
else{
myloopelse(a, ...);
}
}
myloop#(int a, ...){
SomeStuffAboveLoop(...)
while(...){
SomeStuffInsideLoop(...)
//Do what you want for the appropriate #
}
}
您也可以将if
块更改为开关,其他许多答案都会显示。
答案 7 :(得分:0)
在每种情况下采取的操作是否完全相似?在这些情况下,我通常使用if语句来设置关键对象的值或指向对象的指针,然后在剩余的代码中使用这些值......基本上,最大化你对间接的使用。
dim x as object
dy y as string
如果(a == 1)那么
X = foo.object
Y = bar.string
elseif(a == 2)
X = yuk.object
Y = yo.string
结束如果
而... ...
dofunction(X,Y)
结束时
但是,如果你的操作完全不同,那么它已经很难看了,你也可以创建多个循环来节省时钟周期......
答案 8 :(得分:0)
如果条件大多相邻,则可以使用带指针功能的数组。
typedef void ( *case_func )( type1 param1, type2 param2 );
void case_func1( type1 param1, type2 param2 );
void case_func2( type1 param1, type2 param2 );
void case_func3( type1 param1, type2 param2 );
void case_func5( type1 param1, type2 param2 );
case_func func_array[] =
{
&case_func1,
&case_func2,
&case_func3,
NULL, // Just a place holder, for non-contiguous values.
&case_func5
};
int myloop(int a, .....){
/* some stuff */
// Critical loop
while(...)
{
if ( func_array[ a ] && a < sizeof( func_array ) )
func_array[ a ]( .... );
}
}
如果您可以确保数组中没有漏洞且a
永远不会超出数组范围,则可以省略if ( func_array[ a ] && a < sizeof( func_array ) )
,将代码简化为无法进行比较。
无论如何,这种方法可以更清晰一些,即使它没有带来很大的性能提升也值得。
答案 9 :(得分:0)
您还可以考虑在以下条件下移动循环。这会牺牲代码大小来提高运行效率。
if (a == 0) {
while (...) {
/* some stuff */
// 0 stuff
}
} else if (a == 2) {
while (...) {
/* some stuff */
// 2 stuff
}
} else if (a == 3) {
....
}