Один из моих коллег недавно сказал, что вышеприведенное утверждение не является типобезопасным, и я должен использовать что-то еще, так как вам нужно как можно больше типизированных структур, чтобы уменьшить количество возможных ошибок.
Хотя я согласен с тем, чтобы быть безопасным по типу, я немного запутался, так как это тип рассматриваемого кода (изменяются только содержимое и длина данных [])
unsigned char data[] = {1,2,3,4,5};
int data_len = sizeof(data) / sizeof(data[0]);
Где та часть, которая не является безопасной?
Само собой разумеется, кроме комментария, коллега не будет объяснять дальше.
PS: Это используется для копирования данных инициализации в класс из конструктора, здесь нет компилятора C ++ 11, поэтому мы не можем использовать std :: array или другую причудливую инициализацию массива. методы.
Возможно, ваш коллега имел в виду, что использование этого выражения с указателями даст неожиданный результат. Эту ошибку очень часто делают новички. Например
void f( unsigned char data[] )
{
int data_len = sizeof(data) / sizeof(data[0]);
//...
}
//...
unsigned char data[] = {1,2,3,4,5};
f( data );
Так что в общем случае было бы более безопасно использовать функцию шаблона вместо выражения. Например
template <class T, size_t N>
inline size_t size( const T ( & )[N] )
{
return N;
}
Примите во внимание, что есть структура шаблона std::extent
в C ++ 11 это может быть использовано для получения размера измерения.
Например
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;
Одна из возможных проблем заключается в том, что если данные создаются в куче с помощью new, вы не получите длину, а вместо этого какое-то значение, связанное с длиной указателя в системе, в которой вы находитесь.
char* data = new char[5];
//sizeof(data) is dependent on system
sizeof data / sizeof *data
совершенно нормально и небезопасно. Но вы должны быть в состоянии гарантировать, что:
Вы можете получить диагностику, если не предоставили массив с помощью шаблонов:
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;
}
В C параметры массива распадаются на указатели. Итак, выражение sizeof(arr)/sizeof(arr[0])
становится sizeof(int*)/sizeof(int)
что приводит к 1 для машины IA32.
Следовательно, sizeof
не следует использовать для получения количества элементов в таких случаях. Отдельный параметр для размера массива (или длины) должен быть передан fun()
, Таким образом, исправленная программа для печати чисел:
#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;
}