سؤال

One of my colleagues has recently said that the above statement is not type safe and I should use something else as you need as much type safe structures as possible to reduce the amount of possible bugs.

Whilst I agree on being type safe, I'm a little confused as this is the type of code in question (only the contents and length of data[] is modified)

unsigned char data[] = {1,2,3,4,5};
int data_len = sizeof(data) / sizeof(data[0]); 

Where is the part that is not type safe?

Needless to say, other than the comment, the colleague will not explain further.

PS: This is used to copy initialisation data into a class from the constructor, no C++11 compiler exists here, so we can't use std::array or other fancy array initialisation. techniques.

هل كانت مفيدة؟

المحلول

Maybe your colleague meant that using this expression with pointers will give an unexpected result. This mistake is made very often by beginners. For example

void f( unsigned char data[] )
{
   int data_len = sizeof(data) / sizeof(data[0]); 
   //...
}

//...

unsigned char data[] = {1,2,3,4,5};
f( data );

So in general case it would be more safely to use a template function instead of the expression. For example

template <class T, size_t N>

inline size_t size( const T ( & )[N] )
{
   return N;
}

Take into account that there is template structure std::extent in C++ 11 that can be used to get the size of a dimension.

For example

int a[2][4][6];

std::cout << std::extent<decltype( a )>::value << std::endl;
std::cout << std::extent<decltype( a ), 1>::value << std::endl;
std::cout << std::extent<decltype( a ), 2>::value << std::endl;

نصائح أخرى

One possible problem is that if data is created on the heap with new, you won't get the length, instead some value related to the length of a pointer on the system you are on.

char* data = new char[5];

//sizeof(data) is dependent on system

sizeof data / sizeof *data is perfectly fine and typesafe. But you must be able to guaranted that:

  • You really feed it an array, not a pointer
  • Said array is not zero length
    • Up to C99 at least , int[0] would be a constraint violation and thus must be diagnosed. Many compilers allow it as an extension.
    • Up to C++13 at least, the same holds true for C++.

You can get a diagnostic if you didn't provide an array by using templates:

template <typename T, size_t n> inline size_t elements_of(const T&[n])
{
  return n;
}
#include<stdio.h>
void fun(int arr[])  
{
  /* sizeof cannot be used here to get number  of elements in array*/
  int arr_size = sizeof(arr)/sizeof(arr[0]); /* incorrect use of sizeof*/
}

int main()
{
  int arr[4] = {0, 0 ,0, 0};
  fun(arr);  
  return 0;
} 

In C, array parameters decay to pointers. So the expression sizeof(arr)/sizeof(arr[0]) becomes sizeof(int*)/sizeof(int) which results in 1 for IA32 machine.

Therefore, sizeof should not be used to get number of elements in such cases. A separate parameter for array size (or length) must be passed to fun(). So the corrected program for printing the numbers is:

#include<stdio.h>
void fun(int arr[], size_t arr_size)  
{
  int i;   
  for (i = 0; i < arr_size; i++) 
  {  
    arr[i] = i;  
  }
}

int main()
{
  int i;  
  int arr[4] = {0, 0 ,0, 0};
  fun(arr, sizeof arr / sizeof arr[0]);

  for(i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
    printf(" %d ", arr[i]);

  getchar();  
  return 0;
}  
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top