Что-то не так с sizeof (массив) / sizeof (массив [0])?

Один из моих коллег недавно сказал, что вышеприведенное утверждение не является типобезопасным, и я должен использовать что-то еще, так как вам нужно как можно больше типизированных структур, чтобы уменьшить количество возможных ошибок.

Хотя я согласен с тем, чтобы быть безопасным по типу, я немного запутался, так как это тип рассматриваемого кода (изменяются только содержимое и длина данных [])

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

Где та часть, которая не является безопасной?

Само собой разумеется, кроме комментария, коллега не будет объяснять дальше.

PS: Это используется для копирования данных инициализации в класс из конструктора, здесь нет компилятора C ++ 11, поэтому мы не можем использовать std :: array или другую причудливую инициализацию массива. методы.

2

Решение

Возможно, ваш коллега имел в виду, что использование этого выражения с указателями даст неожиданный результат. Эту ошибку очень часто делают новички. Например

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;
5

Другие решения

Одна из возможных проблем заключается в том, что если данные создаются в куче с помощью new, вы не получите длину, а вместо этого какое-то значение, связанное с длиной указателя в системе, в которой вы находитесь.

char* data = new char[5];

//sizeof(data) is dependent on system
2

sizeof data / sizeof *data совершенно нормально и небезопасно. Но вы должны быть в состоянии гарантировать, что:

  • Вы действительно кормите его массивом, а не указателем
  • Указанный массив не нулевой длины
    • По крайней мере, до C99 int [0] будет нарушением ограничения и, следовательно, должно быть диагностировано. Многие компиляторы допускают это как расширение.
    • По крайней мере, до C ++ 13 то же самое относится и к C ++.

Вы можете получить диагностику, если не предоставили массив с помощью шаблонов:

template <typename T, size_t n> inline size_t elements_of(const T&[n])
{
return n;
}
1

#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;
}
-1
По вопросам рекламы [email protected]