Преобразование типа указателя: влияние на длину буфера? - PullRequest
0 голосов
/ 07 февраля 2010

Char равен 1 байту unsigned short составляет 2 байта

Итак, если я приведу char * к unsigned short *, изменится ли длина буфера?

Например, я передаю char * и длину функции VUMeter. Функция приводит char * к unsigned short *:

short* pln = (short*) buffer;`

Теперь я перебираю буфер, поэтому могу ли я использовать ту же длину, которая была передана?

int peak=0;
short* pln = (short*) buffer;
for (int i=0; i<len; i++)
{
  if(abs(pln[i]) > peak)
     peak = abs(pln[i]);
}  

По какой-то причине я получаю ошибки приложения в цикле.

Ответы [ 3 ]

1 голос
/ 07 февраля 2010

Если размер элементов удваивается, то у вас есть место для половины элементов. Приведение указателя не изменяет его размер, в основном предполагает, что вы знаете, что делаете с указателем.

Так что нет, вы не можете на самом деле бросить символ * на короткий * и ожидать, что все будет работать. Если вам нужен short * с теми же значениями, что и в char *, вам нужно выделить короткий массив и скопировать элементы по отдельности из char *.

0 голосов
/ 07 февраля 2010

Распределенная память не изменится, пока вы не вызовете * alloc (). Тот факт, что размер типа данных имеет другой размер, будет влиять только на «размер шага» («x + 1» будет указывать на x + 2 байта), но у вас будет место для половины такого количества элементов.

Лично я бы не стал просто указывать указатель. Это, вероятно, приведет к неправильному прочтению данных, уже присутствующих в блоке памяти (теперь два отдельных байта будут считываться как одно значение, полностью отличающееся от того, что вы имели в виду при заполнении буфера однобайтовыми значениями: два последующих значения 127 127 станет одним значением: 65535, такого рода вещи). И я думаю, что это также вызовет предупреждение в компиляторе (по крайней мере, GCC жалуется на такое приведение). Я думаю, что вы должны сделать это:

int x = SOMEVAL;
char * cptr = malloc(x*sizeof(char));
/* some code here - fill cptr with data */
uint16 * sptr = malloc(x*sizeof(uint16));
int i;
for (i = 0; i < x; i++) {
    *(sptr+i) = (uint16)(*(cptr+i));
}
free(cptr);

Если в моем быстро скомпонованном коде нет какой-либо ошибки (я не удосужился проверить это), он должен делать то, что вы хотите достичь: «привести» указатель из char * в uint16 *, но также безопасно скопировать данные без изменения значений (если среди символов нет отрицательного значения, ofc).

0 голосов
/ 07 февраля 2010

unsigned short может быть или не быть 2 байта. Давайте посмотрим на память для вашего примера.

+---+---+---+     +---+---+---+
|   |   |   | ... |   |   |   |
+---+---+---+     +---+---+---+

|<-------- len bytes -------->|

Если unsigned short имеет длину 2 байта, то у вас есть пространство размером len/2 unsigned short значений. Или, в более общем случае, у вас есть место для значений len/n unsigned short, где n равно sizeof(unsigned short).

Вы не можете привести unsigned char * к unsigned char * и ожидать, что все будет работать переносимо. Теперь, чтобы вычислить peak, это зависит от того, что вы пытаетесь сделать. Если вы хотите найти максимум len unsigned char значений и сохранить его в peak, цикл будет работать по значениям:

size_t i;
unsigned short peak = 0;
for (i=0; i < len; ++i) {
    if (buffer[i] > peak) {
        peak = buffer[i];
    }
}

Если, однако, вы хотите «объединить» значения sizeof(unsigned short) в одно значение unsigned short, то лучшим вариантом будет вычисление чисел вручную.

Предполагая, что len делится на n, и хранилище с прямым порядком байтов, вы можете сделать что-то вроде этого (без проверки):

#include <stdio.h>
#include <limits.h> 

size_t factor = sizeof(unsigned short);
size_t n = len / factor;
size_t i;
unsigned short peak = 0;
if (len % factor != 0) {
    fprintf(stderr, "Extra data at the end\n");
}   
for (i=0; i < n; ++i) {
    size_t j;
    unsigned short test = 0;
    for (j=0; j < factor; ++j) {
        test = (test << CHAR_BIT)  + buffer[i*factor+j];
    }
    if (test > peak) {
        peak = test;
    }
}
...