是否值得声明作为参数传递的数组的(常量)大小?

时间:2011-05-08 04:13:04

标签: c++ optimization

    const int N = 100;

    void function1(int array[]){
        // ...
    }
    void function2(int array[N]){
        // ...
    }

    int main(int argc, char *argv[]){
        int a[N] = {1, 2, 3, ... , 100};
        function1(a);
        function2(a);
        return 0;
    }

由于某些类型的C ++编译器优化(例如,编译器在编译时计算出function2),我想知道function1是否有可能比sizeof(array)更快。

对于C,在此之前已经讨论过相同的主题:Should I declare the expected size of an array passed as function argument?

谢谢!

4 个答案:

答案 0 :(得分:5)

两个版本的功能之间不应有任何性能差异;如果有的话,它可以忽略不计。但是在你的function2()中,N并不意味着什么,因为你可以传递任何大小的数组。函数签名不会对数组大小施加任何约束,这意味着您不知道传递给函数的数组的实际大小。尝试传递大小为50的数组,编译器不会生成任何错误!

要解决该问题,您可以将函数编写为(接受类型为int且大小 100的数组!):

const int N = 100;
void function2(int (&array)[N]) 
{
}

//usage
int a[100];
function2(a);  //correct - size of the array is exactly 100

int b[50];
function2(b);  //error - size of the array is not 100  

您可以通过编写一个接受对类型为T且大小为N的数组的引用的函数模板来概括它:

template<typename T, size_t N>
void fun(T (&array)[N])
{
    //here you know the actual size of the array passed to this function!
    //size of array is : N
    //you can also calculate the size as
     size_t size_array = sizeof(array)/sizeof(T); //size_array turns out to be N
}

//usage
 int a[100];
 fun(a);  //T = int, N = 100  

 std::string s[25];
 fun(s);  //T = std::string, N = 25

 int *b = new [100];
 fun(b); //error - b is not an array!

答案 1 :(得分:2)

大多数编译器的代码通常会将指向数组的指针作为堆栈上的函数参数(或指定的寄存器)传递...其他任何东西都需要将数组的数据复制到函数的参数部分堆栈上的激活记录,根本不会很快。

因此,例如,对于调用function1function2函数的函数范围内的6个整数数组,这两个实现在程序集中看起来类似于以下内容:

leal -24(%ebp), %eax  //store the address of the array in EAX
pushl %eax            //push the address on the stack as the first argument
call function1        //call function1 (or function2)

function1function2中,访问数组将与任何其他指针一样完成。例如,int sum = array[0] + 5;的汇编代码如下所示:

movl 8(%ebp), %eax   //get the pointer to the array off the stack
movl (%eax), %eax    //dereference array[0] and store in EAX
addl $5, %eax        //add 5 to the value in EAX
movl %eax, -4(%ebp)  //store in "sum", which is at [EBP - 4] on the stack

答案 2 :(得分:1)

我不认为传递大小明显有任何区别,因为它不会在任何地方收到,最终会丢失。人们仍然可以访问超出阵列的限制。通常我遵循的最佳做法是将大小作为单独的参数传递。

void doSomething(int *ptrary,int size)
{

}

答案 3 :(得分:0)

没有速度差异,但声明尺寸可能有两个原因,一个是它将作为其他人的文档。另一个原因是,如果你将它声明为参考参数(如Nawaz建议的那样,只是没有模板化),它会阻止其他人传入太小的缓冲区,这太棒了!缺点是它还会阻止传递太大的缓冲区。