Is it worth declaring the (constant) size of an array that is passed as an argument?
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 开发者_StackOverflow中文版has been debated before here: Should I declare the expected size of an array passed as function argument?.
Thank you!
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!
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
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)
{
}
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.
精彩评论