C中的2D动态数组:这3个代码段中哪一个执行得更快?

C中的2D动态数组:这3个代码段中哪一个执行得更快?,c,arrays,dynamic,2d,C,Arrays,Dynamic,2d,gprof在我的系统(MinGW)上不能正常工作,所以我想知道以下哪一个代码段平均来说更有效 我知道C编译器内部会将所有内容转换为指针算术,但是我想知道下面的代码段是否比其他代码段有任何明显的优势 阵列在连续内存中被动态分配为1d阵列,并且可以在运行时重新分配(对于简单的棋盘游戏,玩家可以随时重新定义棋盘大小) 请注意,在每次循环迭代中,必须计算i&j并将其传递到函数集_cell()(gridType是一个简单的结构,带有几个整数和指向另一个单元格结构的指针) 提前谢谢 分配内存 grid =

gprof在我的系统(MinGW)上不能正常工作,所以我想知道以下哪一个代码段平均来说更有效


我知道C编译器内部会将所有内容转换为指针算术,但是我想知道下面的代码段是否比其他代码段有任何明显的优势

阵列在连续内存中被动态分配为1d阵列,并且可以在运行时重新分配(对于简单的棋盘游戏,玩家可以随时重新定义棋盘大小)

请注意,在每次循环迭代中,必须计算i&j并将其传递到函数集_cell()(gridType是一个简单的结构,带有几个整数和指向另一个单元格结构的指针)

提前谢谢

分配内存

grid = calloc( (nrows * ncols), sizeof(gridType) );
gridType *gp1, *gp2;

if ( !grid )
    return;

for (gp1=grid; gp1 < grid+nrows; gp1+=ncols)
    for (gp2=gp1; gp2 < gp1+ncols; gp2++)
        set_cell( gp2, (gp1-grid), (gp2-gp1), !G_OPENED, !G_FOUND, value, NULL );
register int i,j;           // we need to pass those in set_cell()

for (i=0; i<nrows; i++)
    for (j=0; j<ncols; j++)
        set_cell( &grid[i * ncols + j], i, j, !G_OPENED, !G_FOUND, value, NULL);
free( grid );
片段#1(按1D顺序解析)

编辑:
我在第一个循环中修正了#2 form gp1++)到gp1+=ncols),在Paul校正后(thx!)

直到你测量它,你才知道


任何一个好的编译器都可能产生相同的代码,即使它不会产生缓存、Pilleling、预测分支和其他聪明的东西的效果,这意味着仅仅猜测指令的数量是不够的,对于这样的事情,答案将取决于编译器和运行它的机器。您可以尝试每个代码段,并计算每个代码段所需的时间


然而,这是过早优化的一个主要例子。最好的做法是选择看起来最清晰、最易于维护的代码段。从长远来看,这样做比选择在你的机器上速度最快的机器(在别人的机器上可能不是最快的!)所节省的成本要大得多。您需要不同的递增行为;外部循环应为(gp1=grid;gp1

在另外两种方法中,任何关注的编译器几乎肯定会将代码段3转换为与代码段1等价的东西。但事实上,如果不分析他们,就没有办法知道

另外,请记住Knuth的话:“过早优化是万恶之源。我见过以‘优化’为名所造成的伤害比其他所有原因加起来所造成的伤害都要多,包括纯粹的、错误的愚蠢”“编写编译器的人比你聪明(除非你是Knuth或Hofstadter),因此,让编译器完成它的工作,您就可以继续您的工作了。试图编写“聪明”的优化代码通常只会使编译器感到困惑,从而阻止它编写更好、更优化的代码

  • gprof不工作不是一个真正的问题 请原谅。你仍然可以建立一个 基准和度量执行 时间
  • 您可能无法测量任何值 现代CPU的区别
    nrows*ncols
    变得非常 大或重新分配发生 通常情况下,您可能会优化错误的代码部分
  • 这当然是微观优化,因为大部分运行时间最有可能花费在
    set\u cell
    中,其他所有内容都可以由编译器优化为相同或非常相似的代码

  • 我就是这样写的。我觉得它比你的任何一种方式都更短、更清晰、更简单

    int i, j;
    gridType *gp = grid;
    
    for (i = 0; i < nrows; i++)
        for (j = 0; j < ncols; j++)
            set_cell( gp++, i, j, !G_OPENED, !G_FOUND, value, NULL );
    
    inti,j;
    gridType*gp=网格;
    对于(i=0;i
    嗯,考虑到我从上午10点开始整天都在编写代码(包括上面的代码片段),现在已经是凌晨1:30了,这有点像是一个借口:p无论如何,也许你误解了我原来的帖子:我不是说“嘿,伙计们,给我量一下这个”,我只是想看看是否有更熟悉这种东西的人能记住其中一种东西比其他东西有什么显著的优势。你们已经回答过我了,谢谢你们!我认为#1可能有优势,但如果我做对了,我可能应该坚持使用“传统”的#3,它更“令人赏心悦目”,对吧?是的,对我来说#3似乎是最清晰的——可读、可维护和简短。或者,使用Neil回答中的代码,“内部C编译器将所有内容转换为指针算术”--不,它们没有,至少在某种程度上与此无关。是的,
    a[i]
    相当于
    *(a+i)
    ,但这并不意味着
    i
    被指针替换,或者像
    i++
    这样的整数算法被像
    gp1++
    这样的指针算法替换。是的,显然我不是字面上的“一切”意思;)不必担心会混淆编译器,那个必须修复高度优化但不可靠的垃圾的家伙会怎么样,几个月后也很可能是你。我准备使用注释来处理它,但前提是确实有一个具有显著优势的片段(你们明确表示没有):)
    int i, j;
    gridType *gp = grid;
    
    for (i = 0; i < nrows; i++)
        for (j = 0; j < ncols; j++)
            set_cell( gp++, i, j, !G_OPENED, !G_FOUND, value, NULL );