C 移除从循环调用的函数中的开关盒
我有一个名为C 移除从循环调用的函数中的开关盒,c,optimization,switch-statement,function-pointers,C,Optimization,Switch Statement,Function Pointers,我有一个名为blend\u pixels()的函数,其任务是根据指定的混合模式将单个像素混合到另一个像素上。这个函数反过来被任何想要画任何东西的函数调用 问题是该函数是为每个像素调用的,这意味着它每秒调用数千万次,它包含一个switch case语句,遍历所有可能的混合模式,直到找到正确的模式 显然,这比调用直接执行所需操作的函数要慢一些,这就是我试图解决的问题。调用blend\u pixels()的父函数通常只传递一个混合模式,它们自己在调用后作为参数接收,因此我不能让它们调用一个只执行一个混
blend\u pixels()
的函数,其任务是根据指定的混合模式将单个像素混合到另一个像素上。这个函数反过来被任何想要画任何东西的函数调用
问题是该函数是为每个像素调用的,这意味着它每秒调用数千万次,它包含一个switch case语句,遍历所有可能的混合模式,直到找到正确的模式
显然,这比调用直接执行所需操作的函数要慢一些,这就是我试图解决的问题。调用blend\u pixels()
的父函数通常只传递一个混合模式,它们自己在调用后作为参数接收,因此我不能让它们调用一个只执行一个混合模式的小函数。但是,对于父函数的每次调用,只需要执行一次选择(父函数每次调用操作大量像素,而blend\u pixels()
则针对每个像素进行调用,循环遍历所有必要的像素)
函数如下所示:
void blend_pixels(lrgb_t *bg, lrgb_t fg, int32_t p, const int mode)
{
int32_t r, g, b;
switch (mode)
{
case SOLID:
*bg = fg;
break;
case ADD:
r = (fg.r * p >> 15) + bg->r; if (r>ONE) bg->r = ONE; else bg->r = r;
g = (fg.g * p >> 15) + bg->g; if (g>ONE) bg->g = ONE; else bg->g = g;
b = (fg.b * p >> 15) + bg->b; if (b>ONE) bg->b = ONE; else bg->b = b;
break;
case SUB:
r = -(fg.r * p >> 15) + bg->r; if (r<0) bg->r = 0; else bg->r = r;
g = -(fg.g * p >> 15) + bg->g; if (g<0) bg->g = 0; else bg->g = g;
b = -(fg.b * p >> 15) + bg->b; if (b<0) bg->b = 0; else bg->b = b;
break;
case MUL:
... // you get the idea
}
}
“ADD”是枚举中的整数
因此,显然,任何选择混合算法的开关都应该在
父函数
的循环之外进行。但是怎么做呢?您可以使用函数指针来实现这一点
首先为函数指针定义一个typedef:
typedef void (*blend_function)(lrgb_t *, lrgb_t, int32_t);
然后将blend_pixels
的每个部分分解为自己的函数,每个函数都有与typedef相同的参数和返回类型:
void blend_pixels_add(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_sub(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_mult(lrgb_t *bg, lrgb_t fg, int32_t p)
...
然后,在父函数中,可以指定函数指针类型的变量,并为其指定要使用的函数的地址:
void parent_function(lrgb_t *fb, int w, int h, lrgb_t colour, ... int blendingmode)
{
...
blend_function blend;
switch (blendingmode)
{
case ADD:
blend = blend_pixels_add;
break;
case SUB:
blend = blend_pixels_sub;
break;
...
}
for (iy=y0; iy<y1; iy++)
for (ix=x0; ix<x1; ix++)
{
p = some_weighting_formula();
blend(&fb[iy*w+ix], colour, p);
}
}
void parent_函数(lrgb_t*fb,int w,int h,lrgb_t color,…int blendingmode)
{
...
混合函数混合;
开关(混合模式)
{
案例补充:
混合=混合\u像素\u添加;
打破
个案小组:
混合=混合像素;
打破
...
}
对于(iy=y0;iy,您可以使用函数指针来实现这一点
首先为函数指针定义一个typedef:
typedef void (*blend_function)(lrgb_t *, lrgb_t, int32_t);
然后将blend_pixels
的每个部分分解为自己的函数,每个函数都有与typedef相同的参数和返回类型:
void blend_pixels_add(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_sub(lrgb_t *bg, lrgb_t fg, int32_t p)
...
void blend_pixels_mult(lrgb_t *bg, lrgb_t fg, int32_t p)
...
然后,在父函数中,可以指定函数指针类型的变量,并为其指定要使用的函数的地址:
void parent_function(lrgb_t *fb, int w, int h, lrgb_t colour, ... int blendingmode)
{
...
blend_function blend;
switch (blendingmode)
{
case ADD:
blend = blend_pixels_add;
break;
case SUB:
blend = blend_pixels_sub;
break;
...
}
for (iy=y0; iy<y1; iy++)
for (ix=x0; ix<x1; ix++)
{
p = some_weighting_formula();
blend(&fb[iy*w+ix], colour, p);
}
}
void parent_函数(lrgb_t*fb,int w,int h,lrgb_t color,…int blendingmode)
{
...
混合函数混合;
开关(混合模式)
{
案例补充:
混合=混合\u像素\u添加;
打破
个案小组:
混合=混合像素;
打破
...
}
对于(iy=y0;iy解决您的问题,即“它包含一个switch-case语句,它将遍历所有可能的混合模式,直到找到正确的模式为止”,这可能不是真正发生的情况
Switch语句通常被编译成所谓的跳转表。在跳转表中,代码并不是逐项查找正确的语句,而是将Switch()语句的参数用作地址数组中的索引。类似于:
jump_table[SOLID] -> case SOLID address
jump_table[ADD] -> case ADD address
...
因此,在这种实现中,考虑很多很多值的switch语句应该与手工编码的函数指针解决方案一样快,因为这基本上是编译器构建的“它包含一个switch-case语句,它将遍历所有可能的混合模式,直到找到正确的模式。”,这可能不是真正发生的情况
Switch语句通常被编译成所谓的跳转表。在跳转表中,代码并不是逐项查找正确的语句,而是将Switch()语句的参数用作地址数组中的索引。类似于:
jump_table[SOLID] -> case SOLID address
jump_table[ADD] -> case ADD address
...
因此,在这种实现中,考虑了很多很多值的switch语句应该与手工编码的函数指针解决方案一样快,因为这基本上是编译器构建的。使用函数指针进行混合。但是,您是否正确地进行了基准测试?开关实际上慢了多少?不要过早启动优化。但这并不意味着不需要仔细设计你的界面。我希望switch语句速度非常快。正如在一点也不慢一样,“switch case”语句将遍历所有可能的混合模式,直到找到正确的模式"通常不是switch语句背后的代码是如何工作的。它通常被实现为一个跳转表,允许直接跳转到正确的逻辑。我做了仔细的基准测试,总体性能的差异超过10%。所以我要说switch语句相当快,但每秒执行数千万次它比没有switch语句要慢一点也不夸张!我想每次大概需要一到两个周期。使用函数指针进行混合。但是,你是否正确地进行了基准测试?开关实际上慢了多少?不要过早地进行优化。但这并不意味着不需要仔细设计你的界面。我希望开关语句非常快。就像not at al一样l较慢。语句“切换case语句,遍历所有可能的混合模式,直到找到正确的模式”通常不是switch语句背后的代码是如何工作的。它通常被实现为一个跳转表,允许直接跳转到正确的逻辑。我做了仔细的基准测试,总体性能的差异超过10%。所以我要说switch语句相当快,但每秒执行数千万次它比没有switch语句要慢完全是陈述!我想说每次大概需要一到两个周期。再加上dbush的回答:如果不止一个