4
    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;
    }

I was wondering whether function2 has the potential to be faster than function1 due to some type of C++ compiler optimization (e.g., compiler figures out sizeof(array) at compile time).

For C, the same topic has been debated before here: Should I declare the expected size of an array passed as function argument?.

Thank you!

Community
  • 1
  • 1
Chrys
  • 177
  • 1
  • 7

4 Answers4

5

There shouldn't be any performance difference between the two version of functions; if there is any, its negligible. But in your function2(), N doesn't mean anything, because you can pass array of any size. The function signature doesn't put any constraint on array size, that means you don't know the actual size of the array which you pass to the function. Try passing an array of size 50, the compiler will not generate any error!

To fix that problem, you can write the function as (which accepts an array of type int and size exactly 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  

You can generalize that by writing a function template that accepts a reference to an array of type T and size N as:

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!
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • And generate new function instance for each N? Great way to thrash instruction cache and blot up the executable size! – zvrba May 08 '11 at 04:56
  • @zvrba: you're supposing that they will be many different sizes, but since the size needs to be written down somewhere, I doubt than more than a couple will ever be needed, and even then, probably not at the same time anyway. – Matthieu M. May 08 '11 at 10:21
  • This is interesting...With regards to using `int (&array)[N]` as the function argument, what are the actual runtime implications? Is it going to spend time (meaninglessly) asserting the array size every time the function is called, or is it serving only as a means for compile-time (helpful) sanity check? And most importantly, is it going to help the compiler do additional optimizations within the function? I presume a function that is bound to accept only arrays of a given size can be more efficient/optimized than a function that is to be accepting arrays of truly variable size. Thanks! – Chrys May 08 '11 at 16:41
2

Both code with most compilers will typically pass a pointer to the array as the function argument on the stack (or in a designated register) ... anything else would require copying the data for the array into the argument section of the function's activation record on the stack, and that wouldn't be very fast at all.

So for instance, both implementations would look something like the following in assembly for an array of 6 integers that is local in scope to the function calling either function1 or function2:

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)

In either function1 or function2, accessing the array would be done as with any other pointer. For instance, assembly code for int sum = array[0] + 5; would look something like:

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
Jason
  • 31,834
  • 7
  • 59
  • 78
1

I don't think passing the size explicitly makes any difference because it is not received anywhere and just gets lost eventually. One can still access beyond the limits of the array. Usually the best practice I follow is to pass the size as an separate parameter.

void doSomething(int *ptrary,int size)
{

}
Alok Save
  • 202,538
  • 53
  • 430
  • 533
0

There won't be a speed difference, BUT declaring the size might be useful for two other reasons, one being that it will serve as documentation for others. Another reason is that if you declare it as a reference parameter (as Nawaz suggested, only not templated), it will prevent others from passing in a too small buffer, which is great! The downside is that it will also prevent passing a too large buffer.

zvrba
  • 24,186
  • 3
  • 55
  • 65