Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 移除从循环调用的函数中的开关盒_C_Optimization_Switch Statement_Function Pointers - Fatal编程技术网

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的回答:如果不止一个