## Wednesday, January 2, 2013

### Arrays and sizeof fun.

Sizeof arrays is a rather large land mine in c/c++. Even the most experienced coders will often hack out a piece of code and suddenly come to a screeching halt half way in when they realize they are being an idiot(hopeful they realize...).

The problem is that arrays in C are supposed to be well arrays.. but people often use them as shortcut to define some small non-standard chunk of data, and then you have a nice little surprise waiting to happen when your later upgrading or re-factoring or just using that piece of code. (otherwise know as the "30 seconds saved, 3 hours wasted" coding style..)

Here is what happens when you use arrays as a replacement type:
#include <iostream>

void func(char c[5])
{
std::cout << "sizeof(param,5):" << sizeof(c) << std::endl;
}

void func2(char c[14])
{
std::cout << "sizeof(param,14):" << sizeof(c) << std::endl;
}

typedef char Typedefed[5];

void func3(Typedefed c)
{
std::cout << "sizeof(typedef,5):" << sizeof(c) << std::endl;
}

int main()
{
char a[5];

std::cout << "sizeof(local,5):" << sizeof(a) << std::endl;
func(a);
func2(a);
func3(a);
}


Result (yes it does compile even with the char[14] array being handed a char[5], segv surprise.. yummy!):
sizeof(local,5):5
sizeof(param,5):4
sizeof(param,14):4
sizeof(typedef,5):4


So whats going on.. well this is the unfortunate consequence a design decision in the Ansi C standard "6.2.2.1 Lvalues and function designators".

"Except when it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type compatible with wchar_t, an lvalue that has type array of type'' is converted to an expression that has type pointer to type'' that points to the initial element of the array and is not an lvalue. "

So to work around it your forced to take other measures. Generally I believe its a good idea to do it the right way first time and simply create a trivial struct for your primitive type, consider it a slightly bloated version of a typedef. Your alternatives to this are always passing a ref to the array, or always passing its size with it.

#include <iostream>
void wasteful(char* c, std::size_t s)
{
std::cout << "sizeof(c):" << sizeof(c) << std::endl;
std::cout << "sizeof(s):" << sizeof(s) << std::endl;
std::cout << "wasted  :" << sizeof(c) + sizeof(s) - s << std::endl;

std::cout << "used  :" << s << std::endl;
}

void easytoforget(char (&e)[5])
{
std::cout << "sizeof(e):" << sizeof(e) << std::endl;
};

struct Structed
{
Structed(char* a)  { memcpy(a_,a,sizeof(a_)); }

char a_[5];
};

void fixed(Structed e)
{
std::cout << "sizeof(e):" << sizeof(e) << std::endl;
};

int main()
{
char a[5];

std::cout << std::endl << "Solutions:" << std::endl;
wasteful(a, sizeof(a));
easytoforget(a);
fixed(a);
}