2D数组中指向元素的指针减慢了代码的速度

Pointer to element in an 2D array slows down code

本文关键字:代码 速度 指针 2D 元素 数组      更新时间:2023-10-16

我有这段代码访问关于'x'和'y'轴上的点的一些信息。这些信息稍后用于在屏幕上绘制一些点。代码是这样工作的:

//MAX_X_COORD has a value of 169 
//MAX_Y_COORD has a value of 55
void RedrawFromDATAtable() 
{
    COORD pos;
    HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
    if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
    {MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
    bufferdata_ex *  dptr;
    //bufferdata_ex * y_dptr;
    int  * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!
for(short x=0;x<MAX_X_COORD;x++)
    {
        //y_dptr = bridge->DATA[x];
        for(short y=0;y<MAX_Y_COORD;y++) 
        {
            //dptr = (y_dptr+y); //Rewrite to use a constant pointer!
            dptr = &(_bridge->DATA[x][y]);
            if(dptr->InUse==true)
            {
            {
                pos.X = x;
                pos.Y = y;
                SetConsoleCursorPosition(output, pos);
                //haschanged = false;
            }
            if(!(*lcol==dptr->color)) //Need for a new color?
            {   SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}
            char c((char)dptr->sym);
            WriteConsoleA(output, &c, 1, NULL, NULL);
                lcol = &dptr->color;
            }
        }
    }
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}

切入正题!

好吧!所以最近我有一个想法,像这样访问数组会减慢我的代码。据我所知,当你访问数组中的一个元素时,处理器将获取数组的基址,并从那里通过将元素的大小乘以用于查找指定元素地址的索引。我的想法是,如果我让处理器多次这样做,而不是仅仅创建一个指向地址的指针,然后用它来处理元素,那么它会减慢我的代码速度。所以我将代码重写如下:

void RedrawFromDATAtable() 
{
    COORD pos;
    HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
    if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
    {MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
    bufferdata_ex *  dptr;
    bufferdata_ex * y_dptr;
    int  * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!
for(short x=0;x<MAX_X_COORD;x++)
    {
        y_dptr = _bridge->DATA[x];
        for(short y=0;y<MAX_Y_COORD;y++) 
        {
            dptr = (y_dptr+y); //Rewrite to use a constant pointer!
            //dptr = &(bridge->DATA[x][y]);
            if(dptr->InUse==true)
            {
            {
                pos.X = x;
                pos.Y = y;
                SetConsoleCursorPosition(output, pos);
                //haschanged = false;
            }
            if(!(*lcol==dptr->color)) //Need for a new color?
            {   SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}
            char c((char)dptr->sym);
            WriteConsoleA(output, &c, 1, NULL, NULL);
                lcol = &dptr->color;
            }
        }
    }
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}

这个想法对我来说似乎很好,但问题是第一段代码比第二段代码快!所以我的问题是:为什么第一段代码比第二段代码快?

对于那些不喜欢阅读的人:

为什么第一段代码比另一段快?第一个用时0.0919秒,第二个用时0.226秒。

这也是程序集如何处理指针的副本:

    //No pointers
dptr = &(bridge->DATA[x][y]);
001B41C6  mov         eax,dword ptr [this]  
001B41C9  mov         ecx,dword ptr [eax+14h]  
001B41CC  movsx       edx,word ptr [x]  
001B41D0  imul        edx,edx,370h  
001B41D6  lea         eax,[ecx+edx+1D4h]  
001B41DD  movsx       ecx,word ptr [y]  
001B41E1  shl         ecx,4  
001B41E4  add         eax,ecx  
001B41E6  mov         dword ptr [dptr],eax  

//With pointers
//Pointing to DATA[x]
012C41A5  mov         eax,dword ptr [this]  
012C41A8  mov         ecx,dword ptr [eax+14h]  
012C41AB  movsx       edx,word ptr [x]  
012C41AF  imul        edx,edx,370h  
012C41B5  lea         eax,[ecx+edx+1D4h]  
012C41BC  mov         dword ptr [y_dptr],eax 

//Pointing to DATA[x]+y
012C41E0  movsx       eax,word ptr [y]  
012C41E4  shl         eax,4  
012C41E7  add         eax,dword ptr [y_dptr]  
012C41EA  mov         dword ptr [dptr],eax  

除了这部分代码之外,其余部分是相同的。

只看程序集,我们看到了一个额外的mov (y_dptr的赋值)。
看看这是如何在(外部)循环的每次迭代中完成的,并且代码中没有其他差异,这可能是性能下降的原因。除此之外,您的代码中实际上没有任何东西可以利用您试图使用的指针魔法。
使用dptr = (y_dptr+y);通过直接在指针上使用自增(y_dptr++;),可以丢失DPTR或y_dptr。
这是一些你没有使用的指针算术魔法,可以改进