Pereferring函数与数组或指针?

时间:2017-07-22 21:41:56

标签: c++ arrays pointers

我有两个函数,其中一个是带数组的函数,另一个是带指针参数。他们返回相同的结果,但我不知道哪一个更好用。

#define SIZE 1024

int sumA(int a[SIZE][SIZE])
{
  int sum = 0;
  for(int y = 0; y < SIZE; y++)
    for(int x = 0; x < SIZE; x++)
      sum += a[x][y];

  return sum;
}

int sumB(int *a)
{
  int sum[4] = {0, 0, 0, 0};

  for( int i = 0; i < SIZE*SIZE; i += 4 )
  {
      sum[0] += a[i+0];
      sum[1] += a[i+1];
      sum[2] += a[i+2];
      sum[3] += a[i+3];
  }

  return sum[0] + sum[1] + sum[2] + sum[3];
}

4 个答案:

答案 0 :(得分:2)

在这两种情况下,您都是通过引用传递数组,因此没有区别。

你的sum函数显然对传入的数组有很多了解。所以我认为最好强制数组成为函数所期望的类型。

编辑:如果将int [] []类型的变量传入一个接受int指针(int *)的函数,则必须将变量显式地转换为int *,否则编译器将不接受它。 / p>

Therfore

int sumA(int a[SIZE][SIZE])

是两者中最好的。

答案 1 :(得分:1)

loop unrolling开始,

sumB从绩效角度来看会更好。需要注意的是a是否是4的倍数,你没有检查它并且可能导致程序崩溃。

编辑:sumA肯定更好,因为它更严格(它知道确切的尺寸)

答案 2 :(得分:0)

第一种解决方案更安全,但对性能不利:

  1. 循环是为了后续添加内存中每个SIZE * sizeof(int)字节跳转,这对缓存不好
  2. 你必须依赖编译器展开循环,甚至意识到它可以由一个而不是两个来完成
  3. 第二个解决方案进行手动循环展开,其中分布式和变量适用于cpu流水线(如果它首先没有矢量化)并且分支较少。

    两者都得到了矢量化,但第二个更好。 在第一个中,替换循环顺序确实改善了一些事情,但是没有使得到的程序集相等(当它们接近速度时,第二个循环顺序的几倍)。 https://godbolt.org/g/bW1Jkd 我测量了10倍的性能差异(在coliru上使用-O3,使用gcc)支持第二种解决方案。)

    因此我建议将两者混合使用:

    int sumA(int a[SIZE][SIZE])
    {
      static_assert(SIZE % 4 == 0);
      int* flat_a = &(a[0][0]);
    
      int sum[4] = {0, 0, 0, 0};
    
      for( int i = 0; i < SIZE*SIZE; i += 4 )
      {
          sum[0] += flat_a[i+0];
          sum[1] += flat_a[i+1];
          sum[2] += flat_a[i+2];
          sum[3] += flat_a[i+3];
      }
    
      return sum[0] + sum[1] + sum[2] + sum[3];
    }
    

    这不是一个复杂的功能,一切都仍然易于阅读。

    此外,我不认为4常量应该被设为'非魔法',除非展开完全通用,但这需要一些模板魔术。 命名一个值应该表明它可以在不完全破坏所有内容的情况下进行更改。

答案 3 :(得分:0)

在2之间,我会使用更多类型,但正确命名sumB可能是可行的,更通用的:int sumSIZESIZEints(const int*)

与您的预期相反,SIZE的{​​{1}}被忽略,导致

sumA

更加打字的是:

int sumA(int (*a)[SIZE])