分支或ftell()正在减速

Branching or ftell() that is Slowing?

本文关键字:ftell 分支      更新时间:2023-10-16

我在windows操作系统上查看agent .h文件,我想看到没有注释的c++代码。为了更清楚地看到我的旧程序的代码,我把它们分开了,但令我惊讶的是,它只花了2秒钟就完成了。文件的大小是605KB,所以它不是那么糟糕。为什么这么慢。我怀疑是函数ftell()在做这件事,但我真的说不出来。是分支减慢了速度还是ftell()?如果是ftell(),那么将FILE指针抛出的更好方法是什么?

编辑

#include <stdio.h>
#include <time.h>
#define NOT_COMMENT (!DOUBLESLASH_Comment && !ASTERISK_SLASH_Comment)
int main(int argc,char *argv[])
{
    clock_t t1 = clock();
    FILE *input , *output;
    if( fopen_s(&input,argv[1],"r") )
    {
        printf("error opening file %sn",argv[1]);
        return 0;
    }
    if( fopen_s(&output,argv[2],"w") )
    {
        printf("error opening file %sn",argv[2]);
        return 0;
    }
    char c , d;
                                                                //escape flag
    bool DOUBLESLASH_Comment = 0 , ASTERISK_SLASH_Comment = 0 , flag = 0;
    /* single quotes / double quotes */
    int s_QUOTED = 0 , d_QUOTED = 0;
    while( (c=getc(input)) != EOF )
    {
        switch(c)
        {
        case '':
            {
                if( NOT_COMMENT )
                {
                    if( flag == 1 )
                        flag = 0;
                    else
                        flag = 1;
                }
            }break;
        case ''':
            {
                if( NOT_COMMENT && !d_QUOTED )
                {
                    if( !flag )
                    {
                        s_QUOTED++;
                    }
                }
            }break;
        case '"':
            {
                if( NOT_COMMENT && !flag )
                {
                    if( !s_QUOTED )
                    {
                        d_QUOTED++;
                    }
                }
            }break;
        case '/':
            {
                if( NOT_COMMENT && !d_QUOTED )
                {
                    if( (d=getc(input)) == '*' )
                    {
                        ASTERISK_SLASH_Comment = 1;
                    }
                    else if( d == '/' )
                    {
                        DOUBLESLASH_Comment = 1;
                    }
                    else
                    {
                        if( d != EOF )
                        {
                            ungetc(d,input);
                        }
                    }
                }
            }break;
        case '*':
            {
                if( ASTERISK_SLASH_Comment )
                {
                    if( (d=getc(input)) == '/')
                    {
                        if( (c=getc(input)) == EOF )
                            return 0;
                        ASTERISK_SLASH_Comment = 0;
                    }
                    else
                    {
                        if( d != EOF )
                        {
                            ungetc(d,input);
                        }
                    }
                }
            }break;
        case 'n':
            {
                if( DOUBLESLASH_Comment )
                {
                    DOUBLESLASH_Comment = 0;
                }
            }break;
        }
        if( NOT_COMMENT && c != '' ) flag = 0;
        if( d_QUOTED == 2 ) d_QUOTED = 0;
        if( s_QUOTED == 2 ) s_QUOTED = 0;
        if( NOT_COMMENT )
        {
            fprintf(output,"%c",c);
        }
    }
    fclose(input);
    fclose(output);
    clock_t t2 = clock();
    double elapsed = (double)(t2 - t1) / CLOCKS_PER_SEC;
    printf("time elapsed : %fn",elapsed);
}

如果没有在分析器中实际测量代码的速度(并且使用作为输入的文件,因为我使用的文件可能有不同的注释集,等等,从而触发不同的行为),则很难确定。但是看起来您使用fseek( ... )只是为了向后移动一个字符。在这种情况下,为一个字符的前瞻性编写自己的函数将是一个更好的选择。

像这样:

char lookahead = ' ';
bool havelookahead = false;
char getNextChar(FILE *input)
{
    if (havelookahead)
    {
        havelookahead = false;
        return lookahead;
    }
    return getc(input);
}
char peekChar(FILE *input)
{
    if (!havelookahead)
    {
        lookahead = getc(input);
        havelookahead = true;
    }
    return lookahead;
}

然后将循环开头的getc替换为getNextChar,然后用peekChar检查下一个字符(后面跟着一个虚拟的getNextChar()以消耗它)。

对于解析来说,这通常是一个有用的模式——无论是在字符级别还是在令牌级别,因此了解它是如何工作的是很有好处的。

你也可以使用标准的ungetc来"放回"你看过的角色。

这是否会使你的代码运行得更快还很难说,就像我在开头说的。

我无法编译您的代码,因此我无法进行测试。但我怀疑瓶颈是fseek而不是ftell。拒绝字符是解析文件中的常见任务…并且应该由库或带有缓冲的中间层来实现。在这种情况下(拒绝单个字符),您可以使用ungetc来实现。

所以你应该替换

fseek( file , ( ftell(file) - 1 ) , SEEK_SET );

ungetc('*', file);    // ungetc('/', file); the second time.