Двойное чтение из буфера void *

#c

#c

Вопрос:

Пожалуйста, извините за мое непонимание, я новичок в C. Итак, у меня есть void * буфер, который мне calloc нравится:

void * dataBuffer = calloc(samples, sizeof(double));

и хотел бы позже прочитать это так:

double myDoubleDB = dataBuffer[sampleIndex];

но я получаю сообщение об ошибке, потому что они разных типов (void и double).

Как я могу этого добиться? Мой arch — это ARM, и я использую GCC для компиляции

ОБНОВЛЕНИЕ: dataBuffer находится вне моей досягаемости (другая библиотека), и это просто выглядит как void *

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

1. Почему ваш исходный буфер void * ? Что он на самом деле содержит?

Ответ №1:

 double *dataBuffer = calloc(samples, sizeof(double));
  

Обратите внимание, что 2 байт, вероятно, будет недостаточно для double .

Обратите внимание также, что все биты 0 в памяти (как предусмотрено calloc ) не обязательно представляют допустимое double значение (на большинстве платформ это будет, см. IEEE754).

Если вы не можете изменить объявление dataBuffer , вам все равно следует исправить calloc , а затем выполнить приведение (как предложено другими):

 double myDoubleDB = ((double*)dataBuffer)[sampleIndex];
  

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

1. calloc умножает два аргумента, чтобы определить, сколько байтов нужно выделить

2. @pmg: да, и предполагая, что samples это количество элементов массива, Валентин выделил всего 2 байта на элемент.

3. В то время как вы, как правило, правы, обычно (на платформе на основе IEEE 754) это допустимый double (0.0). Но я не сторонник понижения, 1 для правильного размера.

4. пользователь pmg сказал, что подобное приведение небезопасно , есть идеи, почему?

5. @Valentin Radu: Потому что таким образом вы не получаете проверки типа компилятора.

Ответ №2:

Если вы можете сделать это указателем на double в первую очередь, тем лучше.

 double * dataBuffer = calloc(samples, sizeof *dataBuffer);
double myDoubleDB = dataBuffer[sampleIndex];
  

В противном случае просто небезопасно явно преобразовать void* в double* с помощью приведения:

 void * dataBuffer = calloc(samples, sizeof (double));
double myDoubleDB = ((double*)dataBuffer)[sampleIndex];
  

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

1. dataBuffer находится вне моей досягаемости (другая библиотека), и она просто поставляется как void * . Почему небезопасно ? Не могли бы вы, пожалуйста, объяснить или дать мне какую-нибудь ссылку, чтобы прочитать об этом?

2. @ValentinRadu Тогда вы должны были сказать это в своем вопросе, и кастинг — ваш единственный шанс.

3. Если нет других гарантий (которые, возможно, предоставляет другая библиотека), это небезопасно, потому что некоторые требования для double* превышают те же требования для void* : в частности, требования к размеру для одного.

4. @pmg: Не могли бы вы, пожалуйста, уточнить? Как это соотносится с «Указатель на любой … тип может быть преобразован в указатель на void и обратно; результат должен сравниваться с исходным указателем» (6.3.2.3)?

5. Ключевые слова в этой цитате — «преобразовать обратно». Если указатель начинался как double* и был преобразован в void* , его можно безопасно преобразовать обратно в double* . Например, небезопасно (хотя это разрешено и небезопасно при приведении) преобразовывать его в struct tm* .

Ответ №3:

Вам нужно некоторое приведение :

 double myDoubleDB = ((double*)dataBuffer)[sampleIndex];
  

Примечание: для простоты лучше использовать указатель на double вместо void .

Согласно новому обновлению:

Вы можете использовать указатель для уменьшения приведений:

 double *doubleDataBuffer = (double*) dataBuffer;
double myDoubleDB = doubleDataBuffer[sampleIndex];