Преобразование массивов одного типа в другой

#c #c #arrays #pointers #casting

#c #c #массивы #указатели #Кастинг

Вопрос:

В основном у меня есть массив двойников. Я хочу передать этот массив функции (ProcessData), которая будет обрабатывать их как короткие целые числа. Создает ли короткий указатель и указывает его на массив, а затем передает этот указатель функции ok (код 1)?

По сути, это то же самое, что создать короткий массив, перебирать каждый элемент и преобразовывать каждый элемент двойного массива в короткий, а затем передавать указатель на короткий массив (код 2)? Спасибо

 //code 1
//.....
short* shortPtr = (short*)doubleArr;
ProcessData(shortPtr);
 

..

 //code 2
//...
short shortArr [ARRSIZE];
int i;
for (i = 0; i < ARRSIZE; i  )
{
    shortArr[i] = (short)doubleArr[i];
}
ProcessData(shortArr);
 

Комментарии:

1. Нет, это не нормально. Это не одно и то же.

2. Это все равно, что сказать: «Вот последовательность удвоений, но вместо этого представьте, что это последовательность коротких целых чисел. И удачи с этим «.

3. Если a double занимает 8 байт, а a short занимает 2 байта, вы будете разрезать каждый double из них на 4 нерелевантных части.

4. Также, пожалуйста, выберите один язык C или C .

5. Спасибо за ваши ответы. Этот вопрос применим как для C, так и для C . В C мы также используем массивы в виде простых массивов.

Ответ №1:

Вы не можете просто привести, как говорилось в различных комментариях. Но если вы используете итераторы, вы можете получить более или менее тот же эффект:

 void do_something_with_short(short i) {
    /* whatever */
}

template <class Iter>
void do_something(Iter first, Iter last) {
    while (first != last)
        do_something_with_short(*first  );
}
 

Вы можете вызвать эту шаблонную функцию с итераторами в массив любого арифметического типа (фактически, любого типа, который неявно преобразуется в short или, если вы добавляете приведение в точке вызова do_something_with_short , с типом, который требует приведения):

 double data[10]; // needs to be initialized, of course
do_something(std::begin(data), std::end(data));
 

Ответ №2:

Нет, вы не можете этого сделать. Вот хотя бы одна причина, почему:

Массив представляет собой непрерывную последовательность из нескольких выделений памяти, доступ к которым осуществляется с помощью индекса, например

 [----][----][----]
 

Обратите внимание на четыре тире внутри квадратных скобок. Это означает, что в большинстве ситуаций в C / C длина an int составляет четыре байта. Доступ к ячейкам массивов можно получить по их индексу, потому что, если мы знаем адрес памяти первой ячейки ( m ) и знаем, какого размера должна быть каждая ячейка ( c ) — в данном случае четыре байта, мы можем легко найти ячейку памяти любого индекса, выполнив m index * c

 [----][----][----]
^ array[0]


[----][----][----]
 ----  ----  ^ array[2]
 

По сути, именно поэтому указатели в C / C можно рассматривать как массивы, потому что, когда вы обращаетесь к массивам, вы в основном все равно выполняете арифметику указателей.

В большинстве случаев в C / C длина short составляет 2 байта, поэтому для представления его таким же образом

 [--][--][--]
 

Если вы создадите short указатель и попытаетесь использовать его как массив, ожидается, что он будет указывать на что-то, расположенное как указано выше. Если вы попытаетесь его проиндексировать, у него возникнут проблемы: если вы имели дело с массивом shorts , расположение array[2] такое же m 2 * index , как показано ниже

 [--][--][--]
 --  --  ^ array[2] (note moving along four bytes)
 

Но поскольку мы на самом деле имеем дело с массивом целых чисел, произойдет следующее

 [----][----][----]
 ----  ^ array[2] (again moving along four bytes)
 

Что явно неправильно

Ответ №3:

Нет, потому ptr что на самом деле делает что-то вроде ptr = (char*)ptr sizeof *ptr sizeof (char) значением 1 по определению). Таким образом, увеличение double указателя перемещает его (обычно) на 8 байт, в то время как увеличение short указателя перемещает его всего на 2 байта.

Ответ №4:

Предположим, что ваши дети изучают фортепиано и время от времени просят вас отсканировать для них стопку нот, которые им дал их учитель, родившийся в 20 веке (как и вы). Вы берете эти листы в свой офис и загружаете их в ксерокс. Он создает достойные цифровые сканы, которые ваши дети могут использовать на своем пианино, оснащенном сенсорным экраном. Все идет хорошо, пока однажды ребенок не приносит вам старый редкий набор виниловых пластинок. Она отчаянно пытается найти эти мелодии в нотной форме, но просит вас хотя бы скопировать записи. Неопытный в музыкальных вопросах, ты берешь эти диски к себе в офис, загружаешь их в устройство автоматической подачи документов сканера и понимаешь, что ты по уши в … гм… дерьме, только когда слышишь звуки ломающихся виниловых дисков внутри дурацкой машины. Даже если бы ксерокс не был оснащен АПД, и вам пришлось бы вручную размещать все оригиналы на его стеклянном планшете, вряд ли вы получили бы свою долю похвалы, когда отправляли сканы своей дочери.

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

В C разные типы могут отличаться до такой степени, что печатный лист бумаги отличается от компакт-диска. Функция C , ожидающая получения массива short s, обработает любую последовательность байтов / битов как массив short s. Его не волнует, что область памяти фактически заполнена значениями другого типа, имеющими совершенно другое представление, точно так же, как сканер не заботился о содержимом стека в ADF. Предполагать, что функция будет внутренне преобразовывать каждый элемент массива из double в short , — это то же самое, что полагать, что ксерокс включает в себя граммофон и музыканта, который автоматически переписывает виниловые записи в листовую форму. Обратите внимание, что последнее является возможной конструкцией для реального ксерокса, и некоторые другие языки программирования работают подобным образом. Но не существующие реализации 1 C .


1 Теоретически возможна стандартная реализация C / C , которая интерпретировала бы все положения UB на языке в пользу противоположного ответа на ваш вопрос, а не в пользу лучшей производительности. Но это имело бы мало смысла для такого языка, как C / C .