#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];